You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-27 20:29:45 +02:00
Compare commits
14 Commits
android-v1
...
android-v1
Author | SHA1 | Date | |
---|---|---|---|
|
28e00fdf2e | ||
|
3bd0656eab | ||
|
e9af71dd76 | ||
|
73b33e8e32 | ||
|
c2c7efee91 | ||
|
0836fca822 | ||
|
566df5039c | ||
|
559655bf33 | ||
|
0eab23fbcf | ||
|
f334f4f487 | ||
|
00057da17d | ||
|
0a05464013 | ||
|
9ebb574059 | ||
|
d29c3c2466 |
Binary file not shown.
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
@@ -54,7 +54,7 @@ function ExpandIcon(props:any) {
|
||||
|
||||
function ExpandLink(props:any) {
|
||||
return props.hasChildren ? (
|
||||
<StyledExpandLink href="#" data-folder-id={props.folderId} onClick={props.onFolderToggleClick_}>
|
||||
<StyledExpandLink href="#" data-folder-id={props.folderId} onClick={props.onClick}>
|
||||
<ExpandIcon themeId={props.themeId} isVisible={true} isExpanded={props.isExpanded}/>
|
||||
</StyledExpandLink>
|
||||
) : (
|
||||
@@ -115,17 +115,9 @@ class SideBarComponent extends React.Component<Props, State> {
|
||||
this.header_contextMenu = this.header_contextMenu.bind(this);
|
||||
this.onAddFolderButtonClick = this.onAddFolderButtonClick.bind(this);
|
||||
this.folderItem_click = this.folderItem_click.bind(this);
|
||||
this.itemContextMenu = this.itemContextMenu.bind(this);
|
||||
}
|
||||
|
||||
// componentDidUpdate(prevProps:any, _prevState:any) {
|
||||
// const props = this.props as any;
|
||||
// for (const k in this.props) {
|
||||
// if (prevProps[k] !== props[k]) {
|
||||
// console.info('Props', k, props[k]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
onFolderDragStart_(event:any) {
|
||||
const folderId = event.currentTarget.getAttribute('data-folder-id');
|
||||
if (!folderId) return;
|
||||
@@ -412,7 +404,7 @@ class SideBarComponent extends React.Component<Props, State> {
|
||||
selected={selected}
|
||||
data-id={tag.id}
|
||||
data-type={BaseModel.TYPE_TAG}
|
||||
onContextMenu={(event:any) => this.itemContextMenu(event)}
|
||||
onContextMenu={this.itemContextMenu}
|
||||
onClick={() => {
|
||||
this.tagItem_click(tag);
|
||||
}}
|
||||
|
@@ -78,6 +78,7 @@ export const StyledListItemAnchor = styled.a`
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
user-select: none;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export const StyledExpandLink = styled.a`
|
||||
@@ -91,6 +92,7 @@ export const StyledExpandLink = styled.a`
|
||||
width: 16px;
|
||||
max-width: 16px;
|
||||
min-width: 16px;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export const StyledNoteCount = styled.div`
|
||||
|
10
ElectronClient/package-lock.json
generated
10
ElectronClient/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Joplin",
|
||||
"version": "1.2.3",
|
||||
"version": "1.2.4",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1535,7 +1535,7 @@
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": false,
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -1701,7 +1701,7 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
@@ -1817,7 +1817,7 @@
|
||||
},
|
||||
"tar": {
|
||||
"version": "4.4.8",
|
||||
"resolved": false,
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
|
||||
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -6122,7 +6122,7 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Joplin",
|
||||
"version": "1.2.3",
|
||||
"version": "1.2.4",
|
||||
"description": "Joplin for Desktop",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
@@ -125,8 +125,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097579
|
||||
versionName "1.2.2"
|
||||
versionCode 2097582
|
||||
versionName "1.2.5"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
|
@@ -80,8 +80,19 @@
|
||||
<!-- END RN-push-notitication -->
|
||||
<!-- ============================= -->
|
||||
|
||||
<!-- 2018-12-16: Changed android:launchMode from "singleInstance" to "singleTop" for Firebase notification -->
|
||||
<!-- Previously singleInstance was necessary to prevent multiple instance of the RN app from running at the same time, but maybe no longer needed. -->
|
||||
<!--
|
||||
2018-12-16: Changed android:launchMode from "singleInstance" to "singleTop" for Firebase notification
|
||||
Previously singleInstance was necessary to prevent multiple instance of the RN app from running at the same time, but maybe no longer needed.
|
||||
|
||||
2020-10-06: Changed back again to "singleInstance" and notifications still seem to work. Changing to singleInstance
|
||||
to try to fix this bug: https://discourse.joplinapp.org/t/joplin-android-app-looses-nextcloud-sync-settings/10997/6
|
||||
Users would lose their settings, and it's possibly due to multiple instances of the app running at the same time, perhaps
|
||||
due to sharing with the app. When checking the log, it would show "saving settings", then the app startup message, and after the app
|
||||
has started, it would show "setting saved". So basically the app, or one instance of it, has started while settings were being saved
|
||||
|
||||
2020-10-08: Changed back again to "singleTop" as it has worked so far. The multiple instance bug was "fixed" in a different way
|
||||
See ReactNativeClient/root.js for more info about the bug.
|
||||
-->
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
Binary file not shown.
Before Width: | Height: | Size: 14 KiB |
@@ -407,7 +407,9 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
|
||||
this.saveActionQueue(this.state.note.id).processAllNow();
|
||||
|
||||
this.undoRedoService_.off('stackChange', this.undoRedoService_stackChange);
|
||||
// It cannot theoretically be undefined, since componentDidMount should always be called before
|
||||
// componentWillUnmount, but with React Native the impossible often becomes possible.
|
||||
if (this.undoRedoService_) this.undoRedoService_.off('stackChange', this.undoRedoService_stackChange);
|
||||
}
|
||||
|
||||
title_changeText(text) {
|
||||
|
@@ -3,7 +3,6 @@ const { Database } = require('lib/database.js');
|
||||
const { sprintf } = require('sprintf-js');
|
||||
const Resource = require('lib/models/Resource');
|
||||
const { shim } = require('lib/shim.js');
|
||||
const EventEmitter = require('events');
|
||||
|
||||
const structureSql = `
|
||||
CREATE TABLE folders (
|
||||
@@ -127,11 +126,6 @@ class JoplinDatabase extends Database {
|
||||
this.version_ = null;
|
||||
this.tableFieldNames_ = {};
|
||||
this.extensionToLoad = './build/lib/sql-extensions/spellfix';
|
||||
this.eventEmitter_ = new EventEmitter();
|
||||
}
|
||||
|
||||
eventEmitter() {
|
||||
return this.eventEmitter_;
|
||||
}
|
||||
|
||||
initialized() {
|
||||
@@ -349,6 +343,8 @@ class JoplinDatabase extends Database {
|
||||
+ `Expected version: ${existingDatabaseVersions[existingDatabaseVersions.length - 1]}`);
|
||||
}
|
||||
|
||||
this.logger().info(`Upgrading database from version ${fromVersion}`);
|
||||
|
||||
if (currentVersionIndex == existingDatabaseVersions.length - 1) return fromVersion;
|
||||
|
||||
let latestVersion = fromVersion;
|
||||
@@ -359,8 +355,6 @@ class JoplinDatabase extends Database {
|
||||
|
||||
let queries = [];
|
||||
|
||||
this.eventEmitter_.emit('startMigration', { version: targetVersion });
|
||||
|
||||
if (targetVersion == 1) {
|
||||
queries = this.wrapQueries(this.sqlStringToLines(structureSql));
|
||||
}
|
||||
@@ -856,18 +850,32 @@ class JoplinDatabase extends Database {
|
||||
queries.push('CREATE VIRTUAL TABLE notes_spellfix USING spellfix1');
|
||||
}
|
||||
|
||||
queries.push({ sql: 'UPDATE version SET version = ?', params: [targetVersion] });
|
||||
const updateVersionQuery = { sql: 'UPDATE version SET version = ?', params: [targetVersion] };
|
||||
|
||||
queries.push(updateVersionQuery);
|
||||
|
||||
try {
|
||||
await this.transactionExecBatch(queries);
|
||||
} catch (error) {
|
||||
// In some cases listed below, when the upgrade fail it is acceptable (a fallback will be used)
|
||||
// and in those cases, even though it fails, we still want to set the version number so that the
|
||||
// migration is not repeated on next upgrade.
|
||||
let saveVersionAgain = false;
|
||||
|
||||
if (targetVersion === 15 || targetVersion === 18 || targetVersion === 33) {
|
||||
this.logger().warn('Could not upgrade to database v15 or v18 or v33 - FTS feature will not be used', error);
|
||||
saveVersionAgain = true;
|
||||
} else if (targetVersion === 34) {
|
||||
// this.logger().warn('Could not upgrade to database v34 - fuzzy search will not be used', error);
|
||||
this.logger().warn('Could not upgrade to database v34 - fuzzy search will not be used', error);
|
||||
saveVersionAgain = true;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (saveVersionAgain) {
|
||||
this.logger().info('Migration failed with fallback and will not be repeated - saving version number');
|
||||
await this.transactionExecBatch([updateVersionQuery]);
|
||||
}
|
||||
}
|
||||
|
||||
latestVersion = targetVersion;
|
||||
@@ -933,10 +941,13 @@ class JoplinDatabase extends Database {
|
||||
const version = !versionRow ? 0 : versionRow.version;
|
||||
const tableFieldsVersion = !versionRow ? 0 : versionRow.table_fields_version;
|
||||
this.version_ = version;
|
||||
this.logger().info('Current database version', version);
|
||||
this.logger().info('Current database version', versionRow);
|
||||
|
||||
const newVersion = await this.upgradeDatabase(version);
|
||||
this.version_ = newVersion;
|
||||
|
||||
this.logger().info(`New version: ${newVersion}. Previously recorded version: ${tableFieldsVersion}`);
|
||||
|
||||
if (newVersion !== tableFieldsVersion) await this.refreshTableFields(newVersion);
|
||||
|
||||
this.tableFields_ = {};
|
||||
|
@@ -2,7 +2,7 @@ import setUpQuickActions from './setUpQuickActions';
|
||||
import PluginAssetsLoader from './PluginAssetsLoader';
|
||||
|
||||
const React = require('react');
|
||||
const { AppState, Keyboard, NativeModules, BackHandler, Animated, View, StatusBar, Text, Image } = require('react-native');
|
||||
const { AppState, Keyboard, NativeModules, BackHandler, Animated, View, StatusBar } = require('react-native');
|
||||
const SafeAreaView = require('lib/components/SafeAreaView');
|
||||
const { connect, Provider } = require('react-redux');
|
||||
const { BackButtonService } = require('lib/services/back-button.js');
|
||||
@@ -376,7 +376,7 @@ function decryptionWorker_resourceMetadataButNotBlobDecrypted() {
|
||||
ResourceFetcher.instance().scheduleAutoAddResources();
|
||||
}
|
||||
|
||||
async function initialize(dispatch, messageHandler) {
|
||||
async function initialize(dispatch) {
|
||||
shimInit();
|
||||
|
||||
Setting.setConstant('env', __DEV__ ? 'dev' : 'prod');
|
||||
@@ -415,13 +415,8 @@ async function initialize(dispatch, messageHandler) {
|
||||
dbLogger.setLevel(Logger.LEVEL_INFO);
|
||||
}
|
||||
|
||||
const db_startUpgrade = (event) => {
|
||||
messageHandler(`Upgrading database to v${event.version}...`);
|
||||
};
|
||||
|
||||
const db = new JoplinDatabase(new DatabaseDriverReactNative());
|
||||
db.setLogger(dbLogger);
|
||||
db.eventEmitter().on('startMigration', db_startUpgrade);
|
||||
reg.setDb(db);
|
||||
|
||||
reg.dispatch = dispatch;
|
||||
@@ -458,13 +453,9 @@ async function initialize(dispatch, messageHandler) {
|
||||
// await db.clearForTesting();
|
||||
}
|
||||
|
||||
db.eventEmitter().removeListener('startMigration', db_startUpgrade);
|
||||
|
||||
reg.logger().info('Database is ready.');
|
||||
reg.logger().info('Loading settings...');
|
||||
|
||||
messageHandler('Initialising application...');
|
||||
|
||||
await loadKeychainServiceAndSettings(KeychainServiceDriverMobile);
|
||||
|
||||
if (!Setting.value('clientId')) Setting.setValue('clientId', uuid.create());
|
||||
@@ -611,7 +602,6 @@ class AppComponent extends React.Component {
|
||||
|
||||
this.state = {
|
||||
sideMenuContentOpacity: new Animated.Value(0),
|
||||
initMessage: '',
|
||||
};
|
||||
|
||||
this.lastSyncStarted_ = defaultState.syncStarted;
|
||||
@@ -625,52 +615,66 @@ class AppComponent extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
setTimeout(async () => {
|
||||
// We run initialization code with a small delay to give time
|
||||
// to the view to render "please wait" messages.
|
||||
|
||||
// 2020-10-08: It seems the initialisation code is quite fragile in general and should be kept simple.
|
||||
// For example, adding a loading screen as was done in this commit: https://github.com/laurent22/joplin/commit/569355a3182bc12e50a54249882e3d68a72c2b28.
|
||||
// had for effect that sharing with the app would create multiple instances of the app, thus breaking
|
||||
// database access and so on. It's unclear why it happens and how to fix it but reverting that commit
|
||||
// fixed the issue for now.
|
||||
//
|
||||
// Changing app launch mode doesn't help.
|
||||
//
|
||||
// It's possible that it's a bug in React Native, or perhaps the framework expects that the whole app can be
|
||||
// mounted/unmounted or multiple ones can be running at the same time, but the app was not designed in this
|
||||
// way.
|
||||
//
|
||||
// More reports and info about the multiple instance bug:
|
||||
//
|
||||
// https://github.com/laurent22/joplin/issues/3800
|
||||
// https://github.com/laurent22/joplin/issues/3804
|
||||
// https://github.com/laurent22/joplin/issues/3807
|
||||
// https://discourse.joplinapp.org/t/webdav-config-encryption-config-randomly-lost-on-android/11364
|
||||
// https://discourse.joplinapp.org/t/android-keeps-on-resetting-my-sync-and-theme/11443
|
||||
async componentDidMount() {
|
||||
if (this.props.appState == 'starting') {
|
||||
this.props.dispatch({
|
||||
type: 'APP_STATE_SET',
|
||||
state: 'initializing',
|
||||
});
|
||||
|
||||
await initialize(this.props.dispatch, (message) => {
|
||||
this.setState({ initMessage: message });
|
||||
});
|
||||
|
||||
BackButtonService.initialize(this.backButtonHandler_);
|
||||
|
||||
AlarmService.setInAppNotificationHandler(async (alarmId) => {
|
||||
const alarm = await Alarm.load(alarmId);
|
||||
const notification = await Alarm.makeNotification(alarm);
|
||||
this.dropdownAlert_.alertWithType('info', notification.title, notification.body ? notification.body : '');
|
||||
});
|
||||
|
||||
AppState.addEventListener('change', this.onAppStateChange_);
|
||||
|
||||
const sharedData = await ShareExtension.data();
|
||||
if (sharedData) {
|
||||
reg.logger().info('Received shared data');
|
||||
if (this.props.selectedFolderId) {
|
||||
handleShared(sharedData, this.props.selectedFolderId, this.props.dispatch);
|
||||
} else {
|
||||
reg.logger.info('Cannot handle share - default folder id is not set');
|
||||
}
|
||||
}
|
||||
await initialize(this.props.dispatch);
|
||||
|
||||
this.props.dispatch({
|
||||
type: 'APP_STATE_SET',
|
||||
state: 'ready',
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
BackButtonService.initialize(this.backButtonHandler_);
|
||||
|
||||
AlarmService.setInAppNotificationHandler(async (alarmId) => {
|
||||
const alarm = await Alarm.load(alarmId);
|
||||
const notification = await Alarm.makeNotification(alarm);
|
||||
this.dropdownAlert_.alertWithType('info', notification.title, notification.body ? notification.body : '');
|
||||
});
|
||||
|
||||
AppState.addEventListener('change', this.onAppStateChange_);
|
||||
|
||||
const sharedData = await ShareExtension.data();
|
||||
if (sharedData) {
|
||||
reg.logger().info('Received shared data');
|
||||
if (this.props.selectedFolderId) {
|
||||
handleShared(sharedData, this.props.selectedFolderId, this.props.dispatch);
|
||||
} else {
|
||||
reg.logger.info('Cannot handle share - default folder id is not set');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
AppState.removeEventListener('change', this.onAppStateChange_);
|
||||
}
|
||||
|
||||
async componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.showSideMenu !== prevProps.showSideMenu) {
|
||||
Animated.timing(this.state.sideMenuContentOpacity, {
|
||||
toValue: this.props.showSideMenu ? 0.5 : 0,
|
||||
@@ -715,19 +719,8 @@ class AppComponent extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
renderStartupScreen() {
|
||||
return (
|
||||
<View style={{ alignItems: 'center', justifyContent: 'center', flex: 1 }}>
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<Image style={{ marginBottom: 5 }} source={require('./images/StartUpIcon.png')} />
|
||||
<Text style={{ color: '#444444' }}>{this.state.initMessage}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.appState != 'ready') return this.renderStartupScreen();
|
||||
if (this.props.appState != 'ready') return null;
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
|
||||
let sideMenuContent = null;
|
||||
|
@@ -281,29 +281,6 @@ const operations = [
|
||||
iconWidth: 46,
|
||||
iconHeight: 46,
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// Mobile startup icon
|
||||
// ============================================================================
|
||||
|
||||
{
|
||||
source: 7,
|
||||
dest: 'ReactNativeClient/images/StartUpIcon.png',
|
||||
width: 64,
|
||||
height: 64,
|
||||
},
|
||||
{
|
||||
source: 7,
|
||||
dest: 'ReactNativeClient/images/StartUpIcon@2x.png',
|
||||
width: 128,
|
||||
height: 128,
|
||||
},
|
||||
{
|
||||
source: 7,
|
||||
dest: 'ReactNativeClient/images/StartUpIcon@3x.png',
|
||||
width: 192,
|
||||
height: 192,
|
||||
},
|
||||
];
|
||||
|
||||
async function main() {
|
||||
|
@@ -3,7 +3,11 @@
|
||||
{
|
||||
"name": ".",
|
||||
"path": "."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "D:/Web/www/nextcloud/apps/joplin",
|
||||
"path": "D:/Web/www/nextcloud/apps/joplin"
|
||||
},
|
||||
],
|
||||
"settings": {
|
||||
"files.exclude": {
|
||||
|
Reference in New Issue
Block a user