You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Fixed multiple instance issue
This commit is contained in:
		| @@ -918,16 +918,14 @@ async function main() { | ||||
| 		const filePath = options.path; | ||||
|  | ||||
| 		function makeResponse(response) { | ||||
| 			const output = { | ||||
| 			return { | ||||
| 				ok: response.statusCode < 400, | ||||
| 				path: filePath, | ||||
| 				text: () => { return response.statusMessage; }, | ||||
| 				json: () => { return ''; }, | ||||
| 				json: () => { return { message: response.statusCode + ': ' + response.statusMessage }; }, | ||||
| 				status: response.statusCode, | ||||
| 				headers: response.headers, | ||||
| 			} | ||||
| 			console.info(output); | ||||
| 			return output; | ||||
| 			}; | ||||
| 		} | ||||
|  | ||||
| 		const requestOptions = { | ||||
| @@ -948,9 +946,7 @@ async function main() { | ||||
| 					response.pipe(file); | ||||
|  | ||||
| 					file.on('finish', function() { | ||||
| 						console.info('FINISH'); | ||||
| 						file.close(() => { | ||||
| 							console.info('FINISH CLOSE'); | ||||
| 							resolve(makeResponse(response)); | ||||
| 						}); | ||||
| 					}); | ||||
|   | ||||
| @@ -1,18 +0,0 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| # Because all the files in the "lib" directory are included as "lib/file.js" it | ||||
| # means "lib" must be in NODE_PATH, however modifying the global NODE_PATH | ||||
| # variable would be messy. So instead, the path is set temporarily just before running | ||||
| # the app. To do this, this bash wrapper is needed (also a messy solution, but node | ||||
| # path resolution is messy anyway). See https://gist.github.com/branneman/8048520 | ||||
|  | ||||
| # https://stackoverflow.com/questions/59895/getting-the-source-directory-of-a-bash-script-from-within | ||||
| SOURCE="${BASH_SOURCE[0]}" | ||||
| while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink | ||||
|   CLIENT_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" | ||||
|   SOURCE="$(readlink "$SOURCE")" | ||||
|   [[ $SOURCE != /* ]] && SOURCE="$CLIENT_DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located | ||||
| done | ||||
| CLIENT_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" | ||||
|  | ||||
| NODE_PATH="$CLIENT_DIR:$NODE_PATH" node "$CLIENT_DIR/main.js" "$@" | ||||
| @@ -7,7 +7,7 @@ | ||||
|     "url": "https://github.com/laurent22/joplin" | ||||
|   }, | ||||
|   "url": "git://github.com/laurent22/joplin.git", | ||||
|   "version": "0.8.29", | ||||
|   "version": "0.8.30", | ||||
|   "bin": { | ||||
|     "joplin": "./main_launcher.js" | ||||
|   }, | ||||
|   | ||||
| @@ -24,7 +24,8 @@ | ||||
|         android:name=".MainActivity" | ||||
|         android:label="@string/app_name" | ||||
|         android:configChanges="keyboard|keyboardHidden|orientation|screenSize" | ||||
|         android:windowSoftInputMode="adjustResize"> | ||||
|         android:windowSoftInputMode="adjustResize" | ||||
|         android:launchMode="singleInstance"> | ||||
|         <intent-filter> | ||||
|             <action android:name="android.intent.action.MAIN" /> | ||||
|             <category android:name="android.intent.category.LAUNCHER" /> | ||||
|   | ||||
| @@ -1,4 +1,6 @@ | ||||
| @echo off | ||||
| rmdir /s/q android\app\build | ||||
| rmdir /s/q android\build | ||||
| rmdir /s/q android\.gradle | ||||
| rmdir /s/q android\.gradle | ||||
| rmdir /s/q node_modules | ||||
| npm install | ||||
| @@ -88,7 +88,6 @@ ScreenHeaderComponent.defaultProps = { | ||||
|  | ||||
| const ScreenHeader = connect( | ||||
| 	(state) => { | ||||
| 		console.info('CONNECT', state.historyCanGoBack);	 | ||||
| 		return { | ||||
| 			historyCanGoBack: state.historyCanGoBack, | ||||
| 		}; | ||||
|   | ||||
| @@ -13,7 +13,6 @@ import { Root } from './root.js'; | ||||
| function main() { | ||||
| 	AppRegistry.registerComponent('Joplin', () => Root); | ||||
| 	console.ignoredYellowBox = ['Remote debugger']; | ||||
| 	Log.info('START ======================================================================================================'); | ||||
| 	// Note: The final part of the initialization process is in | ||||
| 	// AppComponent.componentDidMount(), when the application is ready. | ||||
| } | ||||
|   | ||||
| @@ -109,9 +109,6 @@ const reducer = (state = defaultState, action) => { | ||||
| 			} | ||||
|  | ||||
| 			newState.historyCanGoBack = navHistory.length >= 2; | ||||
|  | ||||
| 			console.info(navHistory.length, newState.historyCanGoBack); | ||||
|  | ||||
| 			break; | ||||
|  | ||||
| 		// Replace all the notes with the provided array | ||||
| @@ -218,112 +215,125 @@ const AppNavigator = StackNavigator({ | ||||
| 	Notes: { screen: NotesScreen }, | ||||
| 	Note: { screen: NoteScreen }, | ||||
| 	Folder: { screen: FolderScreen }, | ||||
| 	//Folders: { screen: FoldersScreen }, | ||||
| 	Loading: { screen: LoadingScreen }, | ||||
| 	OneDriveLogin: { screen: OneDriveLoginScreen }, | ||||
| 	Log: { screen: LogScreen }, | ||||
| }); | ||||
|  | ||||
| let initializationState_ = 'waiting'; | ||||
|  | ||||
| async function initialize(dispatch) { | ||||
| 	if (initializationState_ != 'waiting') return; | ||||
|  | ||||
| 	initializationState_ = 'in_progress'; | ||||
|  | ||||
| 	shim.fetchBlob = async function(url, options) { | ||||
| 		if (!options || !options.path) throw new Error('fetchBlob: target file path is missing'); | ||||
| 		if (!options.method) options.method = 'GET'; | ||||
|  | ||||
| 		let headers = options.headers ? options.headers : {}; | ||||
| 		let method = options.method ? options.method : 'GET'; | ||||
|  | ||||
| 		let dirs = RNFetchBlob.fs.dirs; | ||||
| 		let localFilePath = options.path; | ||||
| 		if (localFilePath.indexOf('/') !== 0) localFilePath = dirs.DocumentDir + '/' + localFilePath; | ||||
|  | ||||
| 		delete options.path; | ||||
|  | ||||
| 		try { | ||||
| 			let response = await RNFetchBlob.config({ | ||||
| 				path: localFilePath | ||||
| 			}).fetch(method, url, headers); | ||||
|  | ||||
| 			// Returns an object that roughtly compatible with a standard Response object | ||||
| 			let output = { | ||||
| 				ok: response.respInfo.status < 400, | ||||
| 				path: response.data, | ||||
| 				text: response.text, | ||||
| 				json: response.json, | ||||
| 				status: response.respInfo.status, | ||||
| 				headers: response.respInfo.headers, | ||||
| 			}; | ||||
|  | ||||
| 			return output; | ||||
| 		} catch (error) { | ||||
| 			throw new Error('fetchBlob: ' + method + ' ' + url + ': ' + error.toString()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	Setting.setConstant('env', __DEV__ ? 'dev' : 'prod'); | ||||
| 	Setting.setConstant('appId', 'net.cozic.joplin'); | ||||
| 	Setting.setConstant('appType', 'mobile'); | ||||
| 	Setting.setConstant('resourceDir', RNFetchBlob.fs.dirs.DocumentDir); | ||||
|  | ||||
| 	const logDatabase = new Database(new DatabaseDriverReactNative()); | ||||
| 	await logDatabase.open({ name: 'log.sqlite' }); | ||||
| 	await logDatabase.exec(Logger.databaseCreateTableSql()); | ||||
| 	reg.logger().addTarget('database', { database: logDatabase, source: 'm' }); | ||||
|  | ||||
| 	reg.logger().info('===================================='); | ||||
| 	reg.logger().info('Starting application ' + Setting.value('appId') + ' (' + Setting.value('env') + ')'); | ||||
|  | ||||
| 	let db = new JoplinDatabase(new DatabaseDriverReactNative()); | ||||
| 	reg.setDb(db); | ||||
|  | ||||
| 	BaseModel.dispatch = dispatch; | ||||
| 	NotesScreenUtils.dispatch = dispatch; | ||||
| 	BaseModel.db_ = db; | ||||
|  | ||||
| 	BaseItem.loadClass('Note', Note); | ||||
| 	BaseItem.loadClass('Folder', Folder); | ||||
| 	BaseItem.loadClass('Resource', Resource); | ||||
| 	BaseItem.loadClass('Tag', Tag); | ||||
| 	BaseItem.loadClass('NoteTag', NoteTag); | ||||
|  | ||||
| 	try { | ||||
| 		if (Setting.value('env') == 'prod') { | ||||
| 			await db.open({ name: 'joplin.sqlite' }) | ||||
| 		} else { | ||||
| 			await db.open({ name: 'joplin-53.sqlite' }) | ||||
|  | ||||
| 			// await db.exec('DELETE FROM notes'); | ||||
| 			// await db.exec('DELETE FROM folders'); | ||||
| 			// await db.exec('DELETE FROM tags'); | ||||
| 			// await db.exec('DELETE FROM note_tags'); | ||||
| 			// await db.exec('DELETE FROM resources'); | ||||
| 			// await db.exec('DELETE FROM deleted_items'); | ||||
| 		} | ||||
|  | ||||
| 		reg.logger().info('Database is ready.'); | ||||
| 		reg.logger().info('Loading settings...'); | ||||
| 		await Setting.load(); | ||||
|  | ||||
| 		reg.logger().info('Loading folders...'); | ||||
| 		let initialFolders = await Folder.all(); | ||||
|  | ||||
| 		dispatch({ | ||||
| 			type: 'FOLDERS_UPDATE_ALL', | ||||
| 			folders: initialFolders, | ||||
| 		}); | ||||
|  | ||||
| 		dispatch({ | ||||
| 			type: 'APPLICATION_LOADING_DONE', | ||||
| 		}); | ||||
|  | ||||
| 		if (initialFolders.length) { | ||||
| 			const selectedFolder = await Folder.defaultFolder(); | ||||
| 			if (selectedFolder) NotesScreenUtils.openNoteList(selectedFolder.id); | ||||
| 		} | ||||
| 	} catch (error) { | ||||
| 		reg.logger().error('Initialization error:', error); | ||||
| 	} | ||||
|  | ||||
| 	initializationState_ = 'done'; | ||||
|  | ||||
| 	reg.logger().info('Application initialized'); | ||||
| } | ||||
|  | ||||
| class AppComponent extends React.Component { | ||||
|  | ||||
| 	async componentDidMount() { | ||||
|  | ||||
| 		shim.fetchBlob = async function(url, options) { | ||||
| 			if (!options || !options.path) throw new Error('fetchBlob: target file path is missing'); | ||||
| 			if (!options.method) options.method = 'GET'; | ||||
|  | ||||
| 			let headers = options.headers ? options.headers : {}; | ||||
| 			let method = options.method ? options.method : 'GET'; | ||||
|  | ||||
| 			let dirs = RNFetchBlob.fs.dirs; | ||||
| 			let localFilePath = options.path; | ||||
| 			if (localFilePath.indexOf('/') !== 0) localFilePath = dirs.DocumentDir + '/' + localFilePath; | ||||
|  | ||||
| 			delete options.path; | ||||
|  | ||||
| 			try { | ||||
| 				let response = await RNFetchBlob.config({ | ||||
| 					path: localFilePath | ||||
| 				}).fetch(method, url, headers); | ||||
|  | ||||
| 				// Returns an object that roughtly compatible with a standard Response object | ||||
| 				let output = { | ||||
| 					ok: response.respInfo.status < 400, | ||||
| 					path: response.data, | ||||
| 					text: response.text, | ||||
| 					json: response.json, | ||||
| 					status: response.respInfo.status, | ||||
| 					headers: response.respInfo.headers, | ||||
| 				}; | ||||
|  | ||||
| 				return output; | ||||
| 			} catch (error) { | ||||
| 				throw new Error('fetchBlob: ' + method + ' ' + url + ': ' + error.toString()); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		Setting.setConstant('env', __DEV__ ? 'dev' : 'prod'); | ||||
| 		Setting.setConstant('appId', 'net.cozic.joplin'); | ||||
| 		Setting.setConstant('appType', 'mobile'); | ||||
| 		Setting.setConstant('resourceDir', RNFetchBlob.fs.dirs.DocumentDir); | ||||
|  | ||||
| 		const logDatabase = new Database(new DatabaseDriverReactNative()); | ||||
| 		await logDatabase.open({ name: 'log.sqlite' }); | ||||
| 		await logDatabase.exec(Logger.databaseCreateTableSql()); | ||||
| 		reg.logger().addTarget('database', { database: logDatabase, source: 'm' }); | ||||
|  | ||||
| 		reg.logger().info('Starting application ' + Setting.value('appId') + ' (' + Setting.value('env') + ')'); | ||||
|  | ||||
| 		let db = new JoplinDatabase(new DatabaseDriverReactNative()); | ||||
| 		reg.setDb(db); | ||||
|  | ||||
| 		BaseModel.dispatch = this.props.dispatch; | ||||
| 		NotesScreenUtils.dispatch = this.props.dispatch; | ||||
| 		BaseModel.db_ = db; | ||||
|  | ||||
| 		BaseItem.loadClass('Note', Note); | ||||
| 		BaseItem.loadClass('Folder', Folder); | ||||
| 		BaseItem.loadClass('Resource', Resource); | ||||
| 		BaseItem.loadClass('Tag', Tag); | ||||
| 		BaseItem.loadClass('NoteTag', NoteTag); | ||||
|  | ||||
| 		try { | ||||
| 			if (Setting.value('env') == 'prod') { | ||||
| 				await db.open({ name: 'joplin.sqlite' }) | ||||
| 			} else { | ||||
| 				await db.open({ name: 'joplin-53.sqlite' }) | ||||
|  | ||||
| 				// await db.exec('DELETE FROM notes'); | ||||
| 				// await db.exec('DELETE FROM folders'); | ||||
| 				// await db.exec('DELETE FROM tags'); | ||||
| 				// await db.exec('DELETE FROM note_tags'); | ||||
| 				// await db.exec('DELETE FROM resources'); | ||||
| 				// await db.exec('DELETE FROM deleted_items'); | ||||
| 			} | ||||
|  | ||||
| 			reg.logger().info('Database is ready.'); | ||||
| 			reg.logger().info('Loading settings...'); | ||||
| 			await Setting.load(); | ||||
|  | ||||
| 			reg.logger().info('Loading folders...'); | ||||
| 			let initialFolders = await Folder.all(); | ||||
|  | ||||
| 			this.props.dispatch({ | ||||
| 				type: 'FOLDERS_UPDATE_ALL', | ||||
| 				folders: initialFolders, | ||||
| 			}); | ||||
|  | ||||
| 			this.props.dispatch({ | ||||
| 				type: 'APPLICATION_LOADING_DONE', | ||||
| 			}); | ||||
|  | ||||
| 			if (initialFolders.length) { | ||||
| 				const selectedFolder = await Folder.defaultFolder(); | ||||
| 				if (selectedFolder) NotesScreenUtils.openNoteList(selectedFolder.id); | ||||
| 			} | ||||
| 		} catch (error) { | ||||
| 			Log.error('Initialization error:', error); | ||||
| 		} | ||||
| 		await initialize(this.props.dispatch); | ||||
| 	} | ||||
|  | ||||
| 	sideMenu_change(isOpen) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user