SNTextView for iOS

This commit is contained in:
Mo Bitar
2017-09-25 12:45:35 -05:00
parent d5f0e6d8f7
commit 7cd6ed0ff8
19 changed files with 677 additions and 156 deletions

View File

@@ -97,8 +97,8 @@ android {
applicationId "com.standardnotes"
minSdkVersion 19
targetSdkVersion 25
versionCode 3
versionName "0.0.3"
versionCode 4
versionName "0.0.4"
multiDexEnabled true
ndk {
abiFilters "armeabi-v7a", "x86"

View File

@@ -1,8 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.standardnotes"
android:versionCode="3"
android:versionName="0.0.3">
package="com.standardnotes">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

View File

@@ -5,6 +5,7 @@
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
@@ -12,7 +13,6 @@
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
00E356F31AD99517003FC87E /* StandardNotesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* StandardNotesTests.m */; };
0A0CB2FEBD4F4E26904E2C1A /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0752A2CAF82B4C9198CAC803 /* SimpleLineIcons.ttf */; };
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
@@ -34,26 +34,18 @@
2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; };
2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; };
2DCD954D1E0B4F2C00145EB5 /* StandardNotesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* StandardNotesTests.m */; };
308F6AF684F14FBE8906A535 /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 13BC74D00F074F59BBADD45D /* Entypo.ttf */; };
3F3B0F19ED8C44CB9F287156 /* MaterialCommunityIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6314B32C63AC4827A9329AA6 /* MaterialCommunityIcons.ttf */; };
40F325481D4F4F04AC15D0A9 /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 48127930FB1344778C168838 /* libRNVectorIcons.a */; };
4458D6CB9D184CE586F6B281 /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D38724A93AC141D6B51D1356 /* Foundation.ttf */; };
4A03A911D0084A9F94552332 /* MaterialIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 147893EEE8924AA4AE56F3D7 /* MaterialIcons.ttf */; };
5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; };
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
965031D980094619B7DBA0FD /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1F569402A90047A59845394A /* Ionicons.ttf */; };
9A2C235D0ABA4B0CB9A428CA /* libRNKeychain.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDCF33ADCFE845D588CC4E66 /* libRNKeychain.a */; };
ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; };
B299548F9AC848C0A84B3AF8 /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 12E89137A7104D91898C2734 /* FontAwesome.ttf */; };
B3A5C7D4B7AE403EA161544F /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 00457F9447544666906F6C53 /* Zocial.ttf */; };
B5F4669B5B7E45A5BF742774 /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 59DCF8530F2945FFAA0300FD /* Octicons.ttf */; };
C00E89E3E7F949A4AA0F613E /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F30913DACE34E71895FBF91 /* libz.tbd */; };
CD17667C1F795DC100165C83 /* libSNTextView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CD1766781F795AE500165C83 /* libSNTextView.a */; };
CDB58A1F1F6C518E009EF868 /* libReactNativeNavigation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB58A1E1F6C5182009EF868 /* libReactNativeNavigation.a */; };
CDB58A201F6C5193009EF868 /* libRNMail.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB58A161F6C5179009EF868 /* libRNMail.a */; };
CDB58A211F6C51A4009EF868 /* libReactNativeFingerprintScanner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB58A0F1F6C5174009EF868 /* libReactNativeFingerprintScanner.a */; };
CDB58A221F6C5235009EF868 /* libRCTAes.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB58A091F6C516B009EF868 /* libRCTAes.a */; };
DF947D9402FF426FADD85603 /* Feather.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2416263A135F439AA3C5F9D2 /* Feather.ttf */; };
E2AF9A1843594A7D9214736B /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B5409EE82FED4DA9B57CA746 /* EvilIcons.ttf */; };
F0D84FDB75374348BC0017C2 /* libBugsnagReactNative.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFD3F9197A5F41C0904D7E60 /* libBugsnagReactNative.a */; };
/* End PBXBuildFile section */
@@ -254,6 +246,13 @@
remoteGlobalIDString = 358F4ED71D1E81A9004DF814;
remoteInfo = RCTBlob;
};
CD1766771F795AE500165C83 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = CD17664C1F795AE500165C83 /* SNTextView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = CD2830C11F795AB7002B9529;
remoteInfo = SNTextView;
};
CD885F771F70228400B91C20 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 737AF67874434967865855D8 /* BugsnagReactNative.xcodeproj */;
@@ -388,6 +387,7 @@
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = "<group>"; };
B5409EE82FED4DA9B57CA746 /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = "<group>"; };
CD17664C1F795AE500165C83 /* SNTextView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SNTextView.xcodeproj; path = "../vendor/sn-textview/ios/SNTextView.xcodeproj"; sourceTree = "<group>"; };
CDB58A041F6C516B009EF868 /* RCTAes.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAes.xcodeproj; path = "../vendor/react-native-aes/ios/RCTAes.xcodeproj"; sourceTree = "<group>"; };
CDB58A0A1F6C5174009EF868 /* ReactNativeFingerprintScanner.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeFingerprintScanner.xcodeproj; path = "../vendor/react-native-fingerprint-scanner/ios/ReactNativeFingerprintScanner.xcodeproj"; sourceTree = "<group>"; };
CDB58A101F6C5178009EF868 /* RNMail.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNMail.xcodeproj; path = "../vendor/react-native-mail/RNMail.xcodeproj"; sourceTree = "<group>"; };
@@ -411,6 +411,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
CD17667C1F795DC100165C83 /* libSNTextView.a in Frameworks */,
CDB58A221F6C5235009EF868 /* libRCTAes.a in Frameworks */,
CDB58A211F6C51A4009EF868 /* libReactNativeFingerprintScanner.a in Frameworks */,
CDB58A201F6C5193009EF868 /* libRNMail.a in Frameworks */,
@@ -610,6 +611,7 @@
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
CD17664C1F795AE500165C83 /* SNTextView.xcodeproj */,
CDB58A191F6C5182009EF868 /* ReactNativeNavigation.xcodeproj */,
CDB58A101F6C5178009EF868 /* RNMail.xcodeproj */,
CDB58A0A1F6C5174009EF868 /* ReactNativeFingerprintScanner.xcodeproj */,
@@ -678,6 +680,14 @@
name = Products;
sourceTree = "<group>";
};
CD17664D1F795AE500165C83 /* Products */ = {
isa = PBXGroup;
children = (
CD1766781F795AE500165C83 /* libSNTextView.a */,
);
name = Products;
sourceTree = "<group>";
};
CD885F741F70228400B91C20 /* Products */ = {
isa = PBXGroup;
children = (
@@ -952,6 +962,10 @@
ProductGroup = CDB58A641F6C5294009EF868 /* Products */;
ProjectRef = 54ED130E749A46A3B15B27F2 /* RNVectorIcons.xcodeproj */;
},
{
ProductGroup = CD17664D1F795AE500165C83 /* Products */;
ProjectRef = CD17664C1F795AE500165C83 /* SNTextView.xcodeproj */;
},
);
projectRoot = "";
targets = (
@@ -1146,6 +1160,13 @@
remoteRef = ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
CD1766781F795AE500165C83 /* libSNTextView.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libSNTextView.a;
remoteRef = CD1766771F795AE500165C83 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
CD885F781F70228400B91C20 /* libBugsnagReactNative.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
@@ -1253,17 +1274,7 @@
files = (
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
308F6AF684F14FBE8906A535 /* Entypo.ttf in Resources */,
E2AF9A1843594A7D9214736B /* EvilIcons.ttf in Resources */,
B299548F9AC848C0A84B3AF8 /* FontAwesome.ttf in Resources */,
4458D6CB9D184CE586F6B281 /* Foundation.ttf in Resources */,
965031D980094619B7DBA0FD /* Ionicons.ttf in Resources */,
3F3B0F19ED8C44CB9F287156 /* MaterialCommunityIcons.ttf in Resources */,
4A03A911D0084A9F94552332 /* MaterialIcons.ttf in Resources */,
B5F4669B5B7E45A5BF742774 /* Octicons.ttf in Resources */,
0A0CB2FEBD4F4E26904E2C1A /* SimpleLineIcons.ttf in Resources */,
B3A5C7D4B7AE403EA161544F /* Zocial.ttf in Resources */,
DF947D9402FF426FADD85603 /* Feather.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1455,10 +1466,12 @@
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
"$(SRCROOT)/../vendor/react-native-navigation/ios",
"$(SRCROOT)/../node_modules/bugsnag-react-native/cocoa/**",
"$(SRCROOT)/../node_modules/react-native/Libraries/Text",
);
INFOPLIST_FILE = StandardNotes/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -1484,10 +1497,12 @@
"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
"$(SRCROOT)/../vendor/react-native-navigation/ios",
"$(SRCROOT)/../node_modules/bugsnag-react-native/cocoa/**",
"$(SRCROOT)/../node_modules/react-native/Libraries/Text",
);
INFOPLIST_FILE = StandardNotes/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",

View File

@@ -13,6 +13,7 @@
#import "RCCManager.h"
#import <React/RCTRootView.h>
#import <BugsnagReactNative/BugsnagReactNative.h>
#import "RCTTextView.h"
@implementation AppDelegate

View File

@@ -12,7 +12,7 @@
"immutable": "^3.8.1",
"lodash": "^4.17.4",
"react": "16.0.0-beta.5",
"react-native": "^0.48.3",
"react-native": "^0.48.4",
"react-native-keychain": "^1.2.1",
"react-native-search-box": "0.0.11",
"react-native-vector-icons": "^4.3.0"

View File

@@ -38,7 +38,7 @@ export default class GlobalStyles {
theme.active = true;
this.activeTheme = theme;
var constants = this.defaultConstants();
this.setStyles(this.defaultRules(constants), constants, constants.statusBar);
this.setStyles(this.defaultRules(constants), constants, theme.mobileRules.statusBar);
}
}.bind(this));
}
@@ -224,7 +224,7 @@ export default class GlobalStyles {
mainBackgroundColor: "#ffffff",
mainTintColor: "#fb0206",
mainDimColor: "#9d9d9d",
mainTextColor: "black",
mainTextColor: "#000000",
mainTextFontSize: 16,
mainHeaderFontSize: 16,
@@ -318,9 +318,9 @@ export default class GlobalStyles {
},
sectionedAccessoryTableCellLabel: {
paddingTop: 10,
fontSize: constants.mainTextFontSize,
color: constants.mainTextColor,
paddingTop: 12,
},
buttonCell: {
@@ -337,7 +337,11 @@ export default class GlobalStyles {
color: Platform.OS == "android" ? constants.mainTextColor : constants.mainTintColor,
fontSize: constants.mainTextFontSize,
height: "100%",
paddingTop: 10,
paddingTop: 13,
},
buttonCellButtonAndroid: {
paddingTop: 11
},
buttonCellButtonLeft: {
@@ -345,6 +349,24 @@ export default class GlobalStyles {
paddingLeft: constants.paddingLeft
},
noteText: {
flexGrow: 1,
fontSize: 17,
marginTop: 0,
paddingTop: 10,
color: constants.mainTextColor,
paddingLeft: constants.paddingLeft,
paddingRight: constants.paddingLeft,
paddingBottom: 10,
// textAlignVertical: 'top',
// lineHeight: 22,
},
noteTextIOS: {
paddingLeft: constants.paddingLeft - 5,
paddingRight: constants.paddingLeft - 5,
},
bold: {
fontWeight: "bold"
},

View File

@@ -110,6 +110,10 @@ export default class App {
return this.get().isAndroid;
}
static get isIOS() {
return this.get().isIOS;
}
get isAndroid() {
return this._isAndroid;
}
@@ -310,20 +314,6 @@ export default class App {
// recursion
this.isStartingApp = true;
let drawer = {
left: {
screen: 'sn.Filter',
passProps: {
singleSelectMode: true,
options: JSON.stringify(this.optionsState),
onOptionsChange: (options) => {
this.optionsState.mergeWith(options);
}
}
},
disableOpenGesture: false
};
if(this.isIOS) {
let tabs = [{
label: 'Notes',
@@ -343,11 +333,24 @@ export default class App {
animationType: this.isIOS ? 'slide-down' : 'fade',
tabsStyle: _.clone(this.tabStyles), // for iOS
appStyle: _.clone(this.tabStyles), // for Android
drawer: drawer,
animationType: 'none'
}
);
} else {
let drawer = {
left: {
screen: 'sn.Filter',
passProps: {
singleSelectMode: true,
options: JSON.stringify(this.optionsState),
onOptionsChange: (options) => {
this.optionsState.mergeWith(options);
}
}
},
disableOpenGesture: false
};
Navigation.startSingleScreenApp(
{
screen: {

View File

@@ -6,7 +6,7 @@ import GlobalStyles from "../Styles"
export default class ButtonCell extends Component {
rules() {
var rules = [GlobalStyles.styles().buttonCellButton];
var rules = [GlobalStyles.stylesForKey("buttonCellButton")];
if(this.props.leftAligned) { rules.push(GlobalStyles.styles().buttonCellButtonLeft) }
if(this.props.bold) { rules.push(GlobalStyles.styles().bold) }
if(this.props.disabled) { rules.push({color: "gray", opacity: 0.6}) }

View File

@@ -61,6 +61,10 @@ export default class Abstract extends Component {
this.props.navigator.dismissModal({animationType: "slide-down"})
}
viewDidAppear() {
this.visible = true;
}
onNavigatorEvent(event) {
switch(event.id) {
@@ -69,7 +73,7 @@ export default class Abstract extends Component {
this.configureNavBar(false);
break;
case 'didAppear':
this.visible = true;
this.viewDidAppear();
break;
case 'willDisappear':
this.willBeVisible = false;

View File

@@ -104,7 +104,7 @@ export default class Account extends Abstract {
if (event.type == 'NavBarButtonPress') {
if (event.id == 'cancel') {
this.dismissModal();
this.returnToNotesScreen();
}
}
}
@@ -152,6 +152,7 @@ export default class Account extends Abstract {
onRegisterPress = (params, callback) => {
Keyboard.dismiss();
var email = params.email;
var password = params.password;
@@ -197,7 +198,18 @@ export default class Account extends Abstract {
onAuthSuccess = () => {
this.markAllDataDirtyAndSync();
this.dismissModal();
this.returnToNotesScreen();
}
returnToNotesScreen = () => {
if(App.isIOS) {
this.props.navigator.switchToTab({
tabIndex: 0
});
this.forceUpdate();
} else {
this.dismissModal();
}
}
onSignOutPress = () => {

View File

@@ -5,23 +5,18 @@ import ModelManager from '../lib/modelManager'
import Note from '../models/app/note'
import Abstract from "./Abstract"
import Icons from '../Icons';
var dismissKeyboard = require('dismissKeyboard');
import App from '../app'
var _ = require('lodash');
import TextView from "sn-textview";
import {
AppRegistry,
StyleSheet,
TextInput,
View,
FlatList,
TouchableHighlight,
ScrollView,
Text,
Keyboard,
KeyboardAvoidingView,
Platform
Platform,
Keyboard
} from 'react-native';
import GlobalStyles from "../Styles"
@@ -34,50 +29,44 @@ export default class Compose extends Abstract {
constructor(props) {
super(props);
this.state = {};
var note = ModelManager.getInstance().findItem(this.props.noteId);
var note = ModelManager.getInstance().findItem(props.noteId);
if(!note) {
note = new Note({});
note.dummy = true;
}
this.note = note;
this.state = {title: note.title, text: note.text};
this.loadStyles();
this.syncObserver = Sync.getInstance().registerSyncObserver((changesMade, retreived, saved) => {
if(retreived && this.note.uuid && retreived.map((i) => i.uuid).includes(this.note.uuid)) {
this.forceUpdate();
this.mergeState({title: this.note.title, text: this.note.text});
}
});
}
onContentSizeChange = (c) => {
// This function must not be deleted. This is called by TextInput on onContentSizeChange
// It for some reason makes it so that TextInput starts at the top and not the bottom for a long note
}
componentWillMount () {
super.componentWillMount();
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
}
_keyboardDidShow = () => {
this.mergeState({keyboard: true})
}
_keyboardDidHide = () => {
this.mergeState({keyboard: false})
}
componentWillUnmount() {
super.componentWillUnmount();
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
Sync.getInstance().removeSyncObserver(this.syncObserver);
}
viewDidAppear() {
super.viewDidAppear();
// Autofocus doesn't work properly on iOS due to navigation push, so we'll focus manually
if(App.isIOS) {
if(this.note.dummy) {
this.input.focus();
}
}
}
configureNavBar(initial) {
super.configureNavBar();
@@ -90,7 +79,6 @@ export default class Compose extends Abstract {
title: "Manage",
id: 'tags',
showAsAction: 'ifRoom',
// buttonColor: GlobalStyles.constants().mainTintColor,
}
if(Platform.OS === "android") {
@@ -128,6 +116,7 @@ export default class Compose extends Abstract {
}
showOptions() {
this.input.blur();
this.previousOptions = {selectedTags: this.note.tags.map(function(tag){return tag.uuid})};
this.props.navigator.push({
@@ -236,37 +225,24 @@ export default class Compose extends Abstract {
subtitle: title
});
var color = GlobalStyles.constantForKey(App.isIOS ? "mainTextColor" : "navBarTextColor");
this.props.navigator.setStyle({
navBarSubtitleColor: GlobalStyles.hexToRGBA(GlobalStyles.constantForKey("navBarTextColor"), 0.5),
navBarSubtitleColor: GlobalStyles.hexToRGBA(color, 0.5),
navBarSubtitleFontSize: 12
});
}
onTextFocus = () => {
// in order to call blur() later, we need to focus here manually, even though it does nothing
// this.refs.input.focus();
this.isFocused = true;
}
onTextBlur = () => {
this.isFocused = false;
}
render() {
if(this.state.lockContent) {
return (<View></View>);
}
var textBottomPadding = 10;
var keyboardBehavior = Platform.OS == "android" ? "height" : "padding";
var keyboardOffset = this.rawStyles.noteTitle.height + this.rawStyles.noteText.paddingTop + (Platform.OS == "android" ? 15 : 0);
return (
<View style={[this.styles.container, GlobalStyles.styles().container]}>
<TextInput
style={this.styles.noteTitle}
onChangeText={this.onTitleChange}
value={this.note.title}
value={this.state.title}
placeholder={"Add Title"}
selectionColor={GlobalStyles.constants().mainTintColor}
underlineColorAndroid={'transparent'}
@@ -275,10 +251,10 @@ export default class Compose extends Abstract {
{Platform.OS == "android" &&
<View style={this.styles.noteTextContainer}>
<TextView style={this.styles.noteText}
<TextView style={[GlobalStyles.stylesForKey("noteText")]}
ref={(ref) => this.input = ref}
autoFocus={this.note.dummy}
text={this.note.text}
value={this.note.text}
selectionColor={GlobalStyles.lighten(GlobalStyles.constants().mainTintColor)}
onChangeText={this.onTextChange}
/>
@@ -286,27 +262,16 @@ export default class Compose extends Abstract {
}
{Platform.OS == "ios" &&
<KeyboardAvoidingView style={[this.styles.textContainer]} keyboardVerticalOffset={keyboardOffset} behavior={keyboardBehavior}>
<TextInput
style={[this.styles.noteText, {paddingBottom: textBottomPadding}]}
onChangeText={this.onTextChange}
multiline={true}
autoFocus={this.note.dummy}
value={this.note.text}
ref={'input'}
onFocus={this.onTextFocus}
onBlur={this.onTextBlur}
selectionColor={GlobalStyles.constants().mainTintColor}
underlineColorAndroid={'transparent'}
keyboardDismissMode={'interactive'}
textAlignVertical={'top'}
textAlign={'left'}
onScroll={() => {}}
onContentSizeChange={this.onContentSizeChange}
autoCapitalize={'sentences'}
/>
</KeyboardAvoidingView>
<TextView style={[...GlobalStyles.stylesForKey("noteText"), {paddingBottom: 10}]}
ref={(ref) => this.input = ref}
autoFocus={false}
value={this.note.text}
keyboardDismissMode={'interactive'}
selectionColor={GlobalStyles.lighten(GlobalStyles.constants().mainTintColor)}
onChangeText={this.onTextChange}
/>
}
</View>
);
@@ -343,19 +308,8 @@ export default class Compose extends Abstract {
noteTextContainer: {
flexGrow: 1,
flex: 1,
},
noteText: {
flexGrow: 1,
// fontSize: 17,
marginTop: 0,
paddingTop: 10,
color: GlobalStyles.constants().mainTextColor,
paddingLeft: GlobalStyles.constants().paddingLeft,
paddingRight: GlobalStyles.constants().paddingLeft,
// textAlignVertical: 'top',
// lineHeight: 22,
}
}
this.styles = StyleSheet.create(this.rawStyles);

View File

@@ -3,17 +3,12 @@ package com.standardnotes.sntextview;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.text.Editable;
import android.text.Layout;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.LinearLayout;
@@ -26,12 +21,13 @@ import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.Spacing;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.react.views.textinput.ReactEditText;
import java.lang.reflect.Field;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static java.security.AccessController.getContext;
/**
* Created by mo on 9/20/17.
@@ -41,7 +37,8 @@ public class SNTextView extends LinearLayout {
private EditText editText;
private ScrollView scrollView;
private Boolean ignoreNextTextEvent = false;
private Boolean ignoreNextLocalTextChange = false;
private Boolean ignoreNextIncomingTextChange = false;
@SuppressLint("ResourceAsColor")
public SNTextView(Context context) {
@@ -58,19 +55,46 @@ public class SNTextView extends LinearLayout {
editText.setGravity(Gravity.TOP);
editText.addTextChangedListener(new TextWatcher() {
private EventDispatcher mEventDispatcher;
private ReactEditText mEditText;
private String mPreviousText;
@Override
public void afterTextChanged(Editable s) {}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
mPreviousText = s.toString();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(ignoreNextTextEvent) {
ignoreNextTextEvent = false;
// Rearranging the text (i.e. changing between singleline and multiline attributes) can
// also trigger onTextChanged, call the event in JS only when the text actually changed
if (count == 0 && before == 0) {
return;
}
textDidChange(s.toString());
String newText = s.toString().substring(start, start + count);
String oldText = mPreviousText.substring(start, start + before);
// Don't send same text changes
if (count == before && newText.equals(oldText)) {
return;
}
if(ignoreNextLocalTextChange) {
ignoreNextLocalTextChange = false;
return;
}
WritableMap event = Arguments.createMap();
event.putString("text", s.toString());
final Context context = getContext();
if (context instanceof ReactContext) {
((ReactContext) context).getJSModule(RCTEventEmitter.class).receiveEvent(getId(),"onChangeText", event);
}
}
});
@@ -83,9 +107,8 @@ public class SNTextView extends LinearLayout {
super.onLayout(changed, left, top, right, bottom);
}
public void setText(String text) {
ignoreNextTextEvent = true;
ignoreNextLocalTextChange = true;
editText.setText(text);
}
@@ -153,13 +176,4 @@ public class SNTextView extends LinearLayout {
}
}
public void textDidChange(String text) {
WritableMap event = Arguments.createMap();
event.putString("message", editText.getText().toString());
final Context context = getContext();
if (context instanceof ReactContext) {
((ReactContext) context).getJSModule(RCTEventEmitter.class).receiveEvent(getId(),"onChangeTextValue", event);
}
}
}

View File

@@ -117,8 +117,8 @@ public class SNTextViewManager extends SimpleViewManager<SNTextView> {
@Override
public @Nullable Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of(
"onChangeTextValue",
MapBuilder.of("registrationName", "onChangeTextValue")
"onChangeText",
MapBuilder.of("registrationName", "onChangeText")
);
}

View File

@@ -0,0 +1,289 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 48;
objects = {
/* Begin PBXBuildFile section */
CD17667B1F795B1C00165C83 /* SNTextViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = CD17667A1F795B1C00165C83 /* SNTextViewManager.m */; };
CD2830C61F795AB7002B9529 /* SNTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2830C51F795AB7002B9529 /* SNTextView.m */; };
CD2830C71F795AB7002B9529 /* SNTextView.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = CD2830C41F795AB7002B9529 /* SNTextView.h */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
CD2830BF1F795AB7002B9529 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
CD2830C71F795AB7002B9529 /* SNTextView.h in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
CD1766791F795B1C00165C83 /* SNTextViewManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTextViewManager.h; sourceTree = "<group>"; };
CD17667A1F795B1C00165C83 /* SNTextViewManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTextViewManager.m; sourceTree = "<group>"; };
CD2830C11F795AB7002B9529 /* libSNTextView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSNTextView.a; sourceTree = BUILT_PRODUCTS_DIR; };
CD2830C41F795AB7002B9529 /* SNTextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SNTextView.h; sourceTree = "<group>"; };
CD2830C51F795AB7002B9529 /* SNTextView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SNTextView.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
CD2830BE1F795AB7002B9529 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
CD2830B81F795AB7002B9529 = {
isa = PBXGroup;
children = (
CD2830C31F795AB7002B9529 /* SNTextView */,
CD2830C21F795AB7002B9529 /* Products */,
);
sourceTree = "<group>";
};
CD2830C21F795AB7002B9529 /* Products */ = {
isa = PBXGroup;
children = (
CD2830C11F795AB7002B9529 /* libSNTextView.a */,
);
name = Products;
sourceTree = "<group>";
};
CD2830C31F795AB7002B9529 /* SNTextView */ = {
isa = PBXGroup;
children = (
CD2830C41F795AB7002B9529 /* SNTextView.h */,
CD2830C51F795AB7002B9529 /* SNTextView.m */,
CD1766791F795B1C00165C83 /* SNTextViewManager.h */,
CD17667A1F795B1C00165C83 /* SNTextViewManager.m */,
);
path = SNTextView;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
CD2830C01F795AB7002B9529 /* SNTextView */ = {
isa = PBXNativeTarget;
buildConfigurationList = CD2830CA1F795AB7002B9529 /* Build configuration list for PBXNativeTarget "SNTextView" */;
buildPhases = (
CD2830BD1F795AB7002B9529 /* Sources */,
CD2830BE1F795AB7002B9529 /* Frameworks */,
CD2830BF1F795AB7002B9529 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = SNTextView;
productName = SNTextView;
productReference = CD2830C11F795AB7002B9529 /* libSNTextView.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
CD2830B91F795AB7002B9529 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0900;
ORGANIZATIONNAME = standardnotes;
TargetAttributes = {
CD2830C01F795AB7002B9529 = {
CreatedOnToolsVersion = 9.0;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = CD2830BC1F795AB7002B9529 /* Build configuration list for PBXProject "SNTextView" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = CD2830B81F795AB7002B9529;
productRefGroup = CD2830C21F795AB7002B9529 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
CD2830C01F795AB7002B9529 /* SNTextView */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
CD2830BD1F795AB7002B9529 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CD17667B1F795B1C00165C83 /* SNTextViewManager.m in Sources */,
CD2830C61F795AB7002B9529 /* SNTextView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
CD2830C81F795AB7002B9529 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
CD2830C91F795AB7002B9529 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
CD2830CB1F795AB7002B9529 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
CD2830CC1F795AB7002B9529 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
CD2830BC1F795AB7002B9529 /* Build configuration list for PBXProject "SNTextView" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CD2830C81F795AB7002B9529 /* Debug */,
CD2830C91F795AB7002B9529 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CD2830CA1F795AB7002B9529 /* Build configuration list for PBXNativeTarget "SNTextView" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CD2830CB1F795AB7002B9529 /* Debug */,
CD2830CC1F795AB7002B9529 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = CD2830B91F795AB7002B9529 /* Project object */;
}

View File

@@ -0,0 +1,23 @@
//
// SNTextView.h
// SNTextView
//
// Created by mo on 9/25/17.
// Copyright © 2017 standardnotes. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
@interface SNTextView : UITextView
@property (nonatomic, copy) RCTBubblingEventBlock onChangeText;
@property (nonatomic, assign) UIScrollViewKeyboardDismissMode keyboardDismissMode;
@property (nonatomic, assign) CGFloat paddingTop;
@property (nonatomic, assign) CGFloat paddingLeft;
@property (nonatomic, assign) CGFloat paddingRight;
@property (nonatomic, assign) CGFloat paddingBottom;
@end

View File

@@ -0,0 +1,88 @@
//
// SNTextView.m
// SNTextView
//
// Created by mo on 9/25/17.
// Copyright © 2017 standardnotes. All rights reserved.
//
#import "SNTextView.h"
@implementation SNTextView
{
BOOL didLayout;
}
- (instancetype)init {
if(self = [super init]) {
__weak typeof(self) weakself = self;
self.contentInset = UIEdgeInsetsZero;
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
CGSize keyboardSize = [[[note userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets insets = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0);
weakself.contentInset = insets;
weakself.scrollIndicatorInsets = insets;
}];
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillHideNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
UIEdgeInsets insets = UIEdgeInsetsZero;
weakself.contentInset = insets;
weakself.scrollIndicatorInsets = insets;
}];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
// There's an issue where a large blob of text without paragraphs will start at the bottom.
// This makes it go up to the top
if(!didLayout) {
didLayout = true;
[self setContentOffset:CGPointZero];
}
}
- (void)setPaddingTop:(CGFloat)paddingTop
{
_paddingTop = paddingTop;
UIEdgeInsets insets = self.textContainerInset;
[self setPaddingTop:paddingTop left:insets.left bottom:insets.bottom right:insets.right];
}
- (void)setPaddingLeft:(CGFloat)paddingLeft
{
_paddingLeft = paddingLeft;
UIEdgeInsets insets = self.textContainerInset;
[self setPaddingTop:insets.top left:paddingLeft bottom:insets.bottom right:insets.right];
}
- (void)setPaddingBottom:(CGFloat)paddingBottom
{
_paddingBottom = paddingBottom;
UIEdgeInsets insets = self.textContainerInset;
[self setPaddingTop:insets.top left:insets.left bottom:paddingBottom right:insets.right];
}
- (void)setPaddingRight:(CGFloat)paddingRight
{
_paddingRight = paddingRight;
UIEdgeInsets insets = self.textContainerInset;
[self setPaddingTop:insets.top left:insets.left bottom:insets.bottom right:paddingRight];
}
- (void)setPaddingTop:(CGFloat)top left:(CGFloat)left bottom:(CGFloat)bottom right:(CGFloat)right
{
UIEdgeInsets insets = UIEdgeInsetsMake(top, left, bottom, right);
self.textContainerInset = insets;
}
@end

View File

@@ -0,0 +1,13 @@
//
// SNTextViewManager.h
// SNTextView
//
// Created by mo on 9/25/17.
// Copyright © 2017 standardnotes. All rights reserved.
//
#import <React/RCTViewManager.h>
@interface SNTextViewManager : RCTViewManager<UITextViewDelegate>
@end

View File

@@ -0,0 +1,61 @@
//
// SNTextViewManager.m
// SNTextView
//
// Created by mo on 9/25/17.
// Copyright © 2017 standardnotes. All rights reserved.
//
#import "SNTextViewManager.h"
#import "SNTextView.h"
#import <React/RCTFont.h>
@implementation SNTextViewManager
RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(text, NSString)
RCT_EXPORT_VIEW_PROPERTY(onChangeText, RCTBubblingEventBlock)
RCT_REMAP_VIEW_PROPERTY(keyboardDismissMode, keyboardDismissMode, UIScrollViewKeyboardDismissMode)
RCT_REMAP_VIEW_PROPERTY(color, textColor, UIColor)
RCT_REMAP_VIEW_PROPERTY(selectionColor, tintColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(paddingTop, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(paddingRight, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(paddingBottom, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(paddingLeft, CGFloat)
- (UIView *)view
{
SNTextView *textView = [[SNTextView alloc] init];
textView.delegate = self;
return textView;
}
RCT_CUSTOM_VIEW_PROPERTY(fontSize, NSNumber, SNTextView)
{
view.font = [RCTFont updateFont:view.font withSize:json ?: @(defaultView.font.pointSize)];
}
RCT_CUSTOM_VIEW_PROPERTY(fontWeight, NSString, __unused SNTextView)
{
view.font = [RCTFont updateFont:view.font withWeight:json]; // defaults to normal
}
RCT_CUSTOM_VIEW_PROPERTY(fontStyle, NSString, __unused SNTextView)
{
view.font = [RCTFont updateFont:view.font withStyle:json]; // defaults to normal
}
RCT_CUSTOM_VIEW_PROPERTY(fontFamily, NSString, SNTextView)
{
view.font = [RCTFont updateFont:view.font withFamily:json ?: defaultView.font.familyName];
}
# pragma Text View Delegate
- (void)textViewDidBeginEditing:(UITextView *)textView {
}
- (void)textViewDidChange:(SNTextView *)textView
{
textView.onChangeText(@{@"text" : textView.text});
}
@end

View File

@@ -1,14 +1,14 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {requireNativeComponent, View, TextInput, findNodeHandle, UIManager} from 'react-native';
import {requireNativeComponent, View, TextInput, findNodeHandle, UIManager, Platform} from 'react-native';
export default class TextView extends Component {
export default class TextView extends TextInput {
constructor(props) {
super(props);
}
onChangeText = (event) => {
this.props.onChangeText(event.nativeEvent.message);
this.props.onChangeText(event.nativeEvent.text);
}
blur() {
@@ -16,7 +16,26 @@ export default class TextView extends Component {
}
render() {
return <SNTextView ref={(ref) => this.ref = ref} {...this.props} onChangeTextValue={this.onChangeText} />
if(Platform.OS == "android") {
const container =
<SNTextView
{...this.props}
ref={(ref) => this.ref = ref}
text={this.props.value}
onChangeText={this.onChangeText}
/>
return container;
} else {
return (
<SNTextView
{...this.props}
ref={(ref) => this.ref = ref}
text={this.props.value}
onChangeText={this.onChangeText}
/>
)
}
}
}
@@ -24,6 +43,11 @@ TextView.propTypes = {
onChangeText: PropTypes.func,
text: PropTypes.string,
autoFocus: PropTypes.bool,
keyboardDismissMode: PropTypes.oneOf([
'none', // default
'on-drag', // Cross-platform
'interactive', // iOS-only
]),
...TextInput.propTypes
}