1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-06-18 23:07:45 +02:00
Files
.github
Assets
CliClient
Clipper
ElectronClient
Modules
ReactNativeClient
MarkdownEditor
android
ios
lib
commands
components
screens
shared
CameraView.js
Dropdown.js
ItemList.js
ModalDialog.js
SafeAreaView.js
SaveIcon.png
action-button.js
app-nav.js
base-screen.js
checkbox.js
global-style.js
note-body-viewer.js
note-item.js
note-list.js
screen-header.js
select-date-time-dialog.js
side-menu-content-note.js
side-menu-content.js
side-menu.js
hooks
images
joplin-renderer
migrations
models
renderers
services
themes
vendor
ArrayUtils.js
AsyncActionQueue.ts
BaseApplication.js
BaseModel.js
BaseSyncTarget.js
Cache.js
ClipperServer.js
CssUtils.js
DropboxApi.js
EventDispatcher.js
HtmlToMd.js
JoplinError.js
JoplinServerApi.ts
ModelCache.js
ObjectUtils.js
ShareExtension.ts
SyncTargetDropbox.js
SyncTargetFilesystem.js
SyncTargetMemory.js
SyncTargetNextcloud.js
SyncTargetOneDrive.js
SyncTargetOneDriveDev.js
SyncTargetRegistry.js
SyncTargetWebDAV.js
TaskQueue.js
TemplateUtils.js
WebDavApi.js
WelcomeUtils.js
checkPermissions.ts
database-driver-node.js
database-driver-react-native.js
database.js
dialogs.js
envFromArgs.js
eventManager.js
file-api-driver-dropbox.js
file-api-driver-local.js
file-api-driver-memory.js
file-api-driver-onedrive.js
file-api-driver-webdav.js
file-api.js
folders-screen-utils.js
fs-driver-base.js
fs-driver-dummy.js
fs-driver-node.js
fs-driver-rn.js
geolocation-node.js
geolocation-react.js
htmlUtils.js
import-enex-html-gen.js
import-enex-md-gen.js
import-enex.js
joplin-database.js
locale.js
logger.js
markJsUtils.js
markdownUtils.js
markupLanguageUtils.js
mime-utils-types.js
mime-utils.js
net-utils.js
onedrive-api-node-utils.js
onedrive-api.js
package.json
parameters.js
parseUri.js
path-utils.js
poor-man-intervals.js
promise-utils.js
randomClipperPort.js
react-logger.js
reducer.js
registry.js
reserved-ids.js
resourceUtils.js
shareHandler.ts
shim-init-node.js
shim-init-react.js
shim.js
string-utils-common.js
string-utils.js
synchronizer.js
theme.js
time-utils.js
urlUtils.js
uuid.js
welcomeAssets.js
locales
tools
.buckconfig
.flowconfig
.gitattributes
.gitignore
.watchmanconfig
PluginAssetsLoader.ts
app.json
clean_build.bat
gulpfile.js
index.android.js
index.ios.js
index.js
main.js
metro.config.js
package-lock.json
package.json
root.js
setUpQuickActions.ts
Tools
docs
patches
readme
.eslintignore
.eslintrc.js
.gitignore
.travis.yml
BUILD.md
CONTRIBUTING.md
Joplin_install_and_update.sh
LICENSE
README.md
SECURITY.md
_config.yml
appveyor.yml
gulpfile.js
joplin.code-workspace
joplin.sublime-project
lint-staged.config.js
package-lock.json
package.json
tsconfig.dev.json
tsconfig.json
joplin/ReactNativeClient/lib/components/CameraView.js

235 lines
7.2 KiB
JavaScript
Raw Normal View History

import { RNCamera } from 'react-native-camera';
const React = require('react');
const Component = React.Component;
const { connect } = require('react-redux');
const { View, TouchableOpacity, Text, Dimensions } = require('react-native');
2018-10-13 10:32:44 +01:00
const Icon = require('react-native-vector-icons/Ionicons').default;
const { _ } = require('lib/locale.js');
const { shim } = require('lib/shim');
const Setting = require('lib/models/Setting');
2018-10-13 10:32:44 +01:00
2020-02-09 14:51:12 +00:00
Icon.loadFont();
2018-10-13 10:32:44 +01:00
class CameraView extends Component {
constructor() {
super();
const dimensions = Dimensions.get('window');
2018-10-13 10:32:44 +01:00
this.state = {
snapping: false,
ratios: [],
screenWidth: dimensions.width,
screenHeight: dimensions.height,
2018-10-13 10:32:44 +01:00
};
2018-10-13 10:32:44 +01:00
this.back_onPress = this.back_onPress.bind(this);
this.photo_onPress = this.photo_onPress.bind(this);
this.reverse_onPress = this.reverse_onPress.bind(this);
this.ratio_onPress = this.ratio_onPress.bind(this);
this.onCameraReady = this.onCameraReady.bind(this);
this.onLayout = this.onLayout.bind(this);
}
onLayout(event) {
this.setState({
screenWidth: event.nativeEvent.layout.width,
screenHeight: event.nativeEvent.layout.height,
});
2018-10-13 10:32:44 +01:00
}
back_onPress() {
if (this.props.onCancel) this.props.onCancel();
}
reverse_onPress() {
if (this.props.cameraType === RNCamera.Constants.Type.back) {
Setting.setValue('camera.type', RNCamera.Constants.Type.front);
} else {
Setting.setValue('camera.type', RNCamera.Constants.Type.back);
}
}
ratio_onPress() {
if (this.state.ratios.length <= 1) return;
let index = this.state.ratios.indexOf(this.props.cameraRatio);
index++;
if (index >= this.state.ratios.length) index = 0;
Setting.setValue('camera.ratio', this.state.ratios[index]);
}
2018-10-13 10:32:44 +01:00
async photo_onPress() {
if (!this.camera || !this.props.onPhoto) return;
this.setState({ snapping: true });
const result = await this.camera.takePictureAsync({
quality: 0.8,
exif: true,
fixOrientation: true,
2018-10-13 10:32:44 +01:00
});
if (this.props.onPhoto) this.props.onPhoto(result);
this.setState({ snapping: false });
}
async onCameraReady() {
const ratios = await this.camera.getSupportedRatiosAsync();
this.setState({ ratios: ratios });
}
renderButton(onPress, iconName, style) {
let icon = null;
if (typeof iconName === 'string') {
icon = (
<Icon
name={iconName}
style={{
fontSize: 40,
color: 'black',
}}
/>
);
} else {
icon = iconName;
}
return (
<TouchableOpacity onPress={onPress} style={Object.assign({}, style)}>
<View style={{ borderRadius: 32, width: 60, height: 60, borderColor: '#00000040', borderWidth: 1, borderStyle: 'solid', backgroundColor: '#ffffff77', justifyContent: 'center', alignItems: 'center', alignSelf: 'baseline' }}>
{ icon }
</View>
</TouchableOpacity>
);
}
fitRectIntoBounds(rect, bounds) {
const rectRatio = rect.width / rect.height;
const boundsRatio = bounds.width / bounds.height;
const newDimensions = {};
// Rect is more landscape than bounds - fit to width
if (rectRatio > boundsRatio) {
newDimensions.width = bounds.width;
newDimensions.height = rect.height * (bounds.width / rect.width);
} else { // Rect is more portrait than bounds - fit to height
newDimensions.width = rect.width * (bounds.height / rect.height);
newDimensions.height = bounds.height;
}
return newDimensions;
}
cameraRect(ratio) {
// To keep the calculations simpler, it's assumed that the phone is in
// portrait orientation. Then at the end we swap the values if needed.
const splitted = ratio.split(':');
const output = this.fitRectIntoBounds({
width: Number(splitted[1]),
height: Number(splitted[0]),
}, {
width: Math.min(this.state.screenWidth, this.state.screenHeight),
height: Math.max(this.state.screenWidth, this.state.screenHeight),
});
if (this.state.screenWidth > this.state.screenHeight) {
const w = output.width;
output.width = output.height;
output.height = w;
}
return output;
}
2018-10-13 10:32:44 +01:00
render() {
const photoIcon = this.state.snapping ? 'md-checkmark' : 'md-camera';
const displayRatios = shim.mobilePlatform() === 'android' && this.state.ratios.length > 1;
const reverseCameraButton = this.renderButton(this.reverse_onPress, 'md-reverse-camera', { flex: 1, flexDirection: 'row', justifyContent: 'flex-start', marginLeft: 20 });
const ratioButton = !displayRatios ? <View style={{ flex: 1 }}/> : this.renderButton(this.ratio_onPress, <Text style={{ fontWeight: 'bold', fontSize: 20 }}>{Setting.value('camera.ratio')}</Text>, { flex: 1, flexDirection: 'row', justifyContent: 'flex-end', marginRight: 20 });
let cameraRatio = '4:3';
const cameraProps = {};
if (displayRatios) {
cameraProps.ratio = this.props.cameraRatio;
cameraRatio = this.props.cameraRatio;
}
const cameraRect = this.cameraRect(cameraRatio);
cameraRect.left = (this.state.screenWidth - cameraRect.width) / 2;
cameraRect.top = (this.state.screenHeight - cameraRect.height) / 2;
2018-10-13 10:32:44 +01:00
return (
<View style={Object.assign({}, this.props.style, { position: 'relative' })} onLayout={this.onLayout}>
<View style={{ position: 'absolute', backgroundColor: '#000000', width: '100%', height: '100%' }}/>
2018-10-13 10:32:44 +01:00
<RNCamera
style={Object.assign({ position: 'absolute' }, cameraRect)}
ref={ref => {
this.camera = ref;
}}
type={this.props.cameraType}
2019-06-14 22:31:01 +01:00
captureAudio={false}
onCameraReady={this.onCameraReady}
2019-06-14 22:31:01 +01:00
androidCameraPermissionOptions={{
title: _('Permission to use camera'),
message: _('Your permission to use your camera is required.'),
buttonPositive: _('OK'),
buttonNegative: _('Cancel'),
}}
{ ...cameraProps }
2018-10-13 10:32:44 +01:00
>
<View style={{ flex: 1, justifyContent: 'space-between', flexDirection: 'column' }}>
<View style={{ flex: 1, justifyContent: 'flex-start' }}>
2018-10-13 10:32:44 +01:00
<TouchableOpacity onPress={this.back_onPress}>
<View style={{ marginLeft: 5, marginTop: 5, borderColor: '#00000040', borderWidth: 1, borderStyle: 'solid', borderRadius: 90, width: 50, height: 50, display: 'flex', backgroundColor: '#ffffff77', justifyContent: 'center', alignItems: 'center' }}>
<Icon
name={'md-arrow-back'}
style={{
fontSize: 40,
color: 'black',
}}
/>
2018-10-13 10:32:44 +01:00
</View>
</TouchableOpacity>
</View>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'flex-end' }}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', marginBottom: 20 }}>
{ reverseCameraButton }
<TouchableOpacity onPress={this.photo_onPress}>
<View style={{ flexDirection: 'row', borderRadius: 90, width: 90, height: 90, backgroundColor: '#ffffffaa', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Icon
name={photoIcon}
style={{
fontSize: 60,
color: 'black',
}}
/>
</View>
</TouchableOpacity>
{ ratioButton }
</View>
2018-10-13 10:32:44 +01:00
</View>
</View>
</RNCamera>
</View>
);
}
}
const mapStateToProps = state => {
return {
cameraRatio: state.settings['camera.ratio'],
cameraType: state.settings['camera.type'],
};
};
module.exports = connect(mapStateToProps)(CameraView);