You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Handle default folder on react-native
This commit is contained in:
		| @@ -35,6 +35,8 @@ class NotesScreenComponent extends React.Component { | ||||
| 				type: 'Navigation/NAVIGATE', | ||||
| 				routeName: 'Folders', | ||||
| 			}); | ||||
| 		}).catch((error) => { | ||||
| 			alert(error.message); | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -53,8 +53,9 @@ class SideMenuContentComponent extends Component { | ||||
| 		let buttons = []; | ||||
| 		for (let i = 0; i < this.props.folders.length; i++) { | ||||
| 			let f = this.props.folders[i]; | ||||
| 			let title = f.title + (f.is_default ? ' *' : ''); | ||||
| 			buttons.push( | ||||
| 				<Button style={styles.button} title={f.title} onPress={() => { this.folder_press(f) }} key={f.id} /> | ||||
| 				<Button style={styles.button} title={title} onPress={() => { this.folder_press(f) }} key={f.id} /> | ||||
| 			); | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import SQLite from 'react-native-sqlite-storage'; | ||||
| import { Log } from 'src/log.js'; | ||||
| import { uuid } from 'src/uuid.js'; | ||||
| import { promiseChain } from 'src/promise-chain.js'; | ||||
| import { _ } from 'src/locale.js' | ||||
|  | ||||
| const structureSql = ` | ||||
| CREATE TABLE folders ( | ||||
| @@ -9,7 +10,8 @@ CREATE TABLE folders ( | ||||
| 	parent_id TEXT NOT NULL DEFAULT "", | ||||
| 	title TEXT NOT NULL DEFAULT "", | ||||
| 	created_time INT NOT NULL DEFAULT 0, | ||||
| 	updated_time INT NOT NULL DEFAULT 0 | ||||
| 	updated_time INT NOT NULL DEFAULT 0, | ||||
| 	is_default BOOLEAN NOT NULL DEFAULT 0 | ||||
| ); | ||||
|  | ||||
| CREATE TABLE notes ( | ||||
| @@ -117,7 +119,7 @@ class Database { | ||||
| 	} | ||||
|  | ||||
| 	open() { | ||||
| 		this.db_ = SQLite.openDatabase({ name: '/storage/emulated/0/Download/joplin-27.sqlite' }, (db) => { | ||||
| 		this.db_ = SQLite.openDatabase({ name: '/storage/emulated/0/Download/joplin-32.sqlite' }, (db) => { | ||||
| 			Log.info('Database was open successfully'); | ||||
| 		}, (error) => { | ||||
| 			Log.error('Cannot open database: ', error); | ||||
| @@ -373,6 +375,7 @@ class Database { | ||||
| 					tx.executeSql(statements[i]); | ||||
| 				} | ||||
| 				tx.executeSql('INSERT INTO settings (`key`, `value`, `type`) VALUES ("clientId", "' + uuid.create() + '", "' + Database.enumId('settings', 'string') + '")'); | ||||
| 				tx.executeSql('INSERT INTO folders (`id`, `title`, `is_default`, `created_time`) VALUES ("' + uuid.create() + '", "' + _('Default list') + '", 1, ' + Math.round((new Date()).getTime() / 1000) + ')'); | ||||
| 			}).then(() => { | ||||
| 				Log.info('Database schema created successfully'); | ||||
| 				// Calling initialize() now that the db has been created will make it go through | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import { BaseModel } from 'src/base-model.js'; | ||||
| import { Log } from 'src/log.js'; | ||||
| import { promiseChain } from 'src/promise-chain.js'; | ||||
| import { Note } from 'src/models/note.js'; | ||||
| import { _ } from 'src/locale.js'; | ||||
|  | ||||
| class Folder extends BaseModel { | ||||
|  | ||||
| @@ -40,7 +41,13 @@ class Folder extends BaseModel { | ||||
| 	} | ||||
|  | ||||
| 	static delete(folderId, options = null) { | ||||
| 		return this.noteIds(folderId).then((ids) => { | ||||
| 		return this.load(folderId).then((folder) => { | ||||
| 			if (!!folder.is_default) { | ||||
| 				throw new Error(_('Cannot delete the default list')); | ||||
| 			} | ||||
| 		}).then(() => { | ||||
| 			return this.noteIds(folderId); | ||||
| 		}).then((ids) => { | ||||
| 			let chain = []; | ||||
| 			for (let i = 0; i < ids.length; i++) { | ||||
| 				chain.push(() => { | ||||
|   | ||||
| @@ -20,7 +20,7 @@ class Registry { | ||||
|  | ||||
| 	static api() { | ||||
| 		if (this.api_) return this.api_; | ||||
| 		this.api_ = new WebApi('http://192.168.1.2'); | ||||
| 		this.api_ = new WebApi('http://192.168.1.3'); | ||||
| 		return this.api_; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -9,94 +9,6 @@ use AppBundle\Controller\ApiController; | ||||
| use AppBundle\Model\Change; | ||||
| use AppBundle\Exception\UnauthorizedException; | ||||
|  | ||||
| /* | ||||
|  | ||||
| JS | ||||
|  | ||||
|  | ||||
| class Session | ||||
| 	::login() | ||||
|  | ||||
| class Synchronizer | ||||
| 	::fromId(id) | ||||
|  | ||||
| class Note | ||||
|  | ||||
| class User | ||||
|  | ||||
|  | ||||
| HISTORY | ||||
|  | ||||
| client_id, create, type, id => get full object from api | ||||
| update, type, id => get full object from api | ||||
| delete, type, id => remove object | ||||
|  | ||||
| Revisions | ||||
| ---------------- | ||||
| id | ||||
| client_id | ||||
| (user_id ?) | ||||
| action (create, update, delete) | ||||
| item_type (note, folder) | ||||
| item_field (title, body, completed...) | ||||
| item_id | ||||
|  | ||||
| if current client ID = revision.client_id - skip | ||||
|  | ||||
| Current client id = 123 | ||||
|  | ||||
| Client ID | Action | Item ID | ||||
| ------------------------------------ | ||||
| 456         delete   777 | ||||
| 123         update   777 - conflict - move to folder - note that deleted by X and then modified by Y | ||||
|  | ||||
|  | ||||
| Client ID | Action | Item ID         | Rev ID | ||||
| ------------------------------------------------------ | ||||
| 456         update   777             | 2 | ||||
| 123         update   777 - conflict  | 3 | ||||
|  | ||||
| Find rev 1 and do three way merge with 2 and 3 - means there's a need to store history of all versions of body/title | ||||
|  | ||||
|  | ||||
|  | ||||
| // Each item should have a revision ID. | ||||
| // When processing revisions => if item revision = revision.id - skip | ||||
|  | ||||
|  | ||||
| API CALL | ||||
|  | ||||
| /synchronizer/?rev_id=<rev_id_that_caller_synched_to> | ||||
|  | ||||
| SIMPLE IMPLEMENTATION: | ||||
|  | ||||
| loop through changes | ||||
| create list of actions: | ||||
| 	create one action per item ID / field (by merging all into one) | ||||
|  | ||||
| loop through actions | ||||
| skip current client id = action.client_id | ||||
|  | ||||
| send back list: | ||||
|  | ||||
| { | ||||
| 	sync_id: 132456, | ||||
| 	notes: [ | ||||
| 		{ | ||||
| 			action: 'update', | ||||
| 			field: 'body', | ||||
| 			body: 'blabla' | ||||
| 		} | ||||
| 	], | ||||
| 	has_more: true | ||||
| } | ||||
|  | ||||
| If has_more, resume with last sync_id | ||||
|  | ||||
|  | ||||
|  | ||||
| */ | ||||
|  | ||||
| class SynchronizerController extends ApiController { | ||||
|  | ||||
| 	/** | ||||
| @@ -108,8 +20,6 @@ class SynchronizerController extends ApiController { | ||||
| 		if (!$this->user() || !$this->session()) throw new UnauthorizedException(); | ||||
|  | ||||
| 		$actions = Change::changesDoneAfterId($this->user()->id, $this->session()->client_id, $lastChangeId); | ||||
| 		// $actions['user_id'] = Change::hex($this->user()->id); | ||||
| 		// $actions['client_id'] = Change::hex($this->session()->client_id); | ||||
| 		return static::successResponse($actions); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -10,6 +10,14 @@ class Session extends BaseModel { | ||||
| 	public $useUuid = true; | ||||
| 	public $incrementing = false; | ||||
|  | ||||
| 	static protected $fields = array( | ||||
| 		'id' => array('public' => 'string'), | ||||
| 		'created_time' => array('public' => 'int'), | ||||
| 		'updated_time' => array('public' => 'int'), | ||||
| 		'owner_id' => array('public' => 'string'), | ||||
| 		'client_id' => array('public' => 'string'), | ||||
| 	); | ||||
|  | ||||
| 	static public function hashPassword($password) { | ||||
| 		return password_hash($password, PASSWORD_DEFAULT); | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user