1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-12-08 23:07:32 +02:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Helmut K. C. Tessarek
417a3b05b9 ci: improve workflow
1. Run tests, iff the other prerequisites are met
2. In case of a translation PR, skip tests not related to translations
2024-12-03 16:27:56 -05:00
2886 changed files with 182395 additions and 653850 deletions

View File

@@ -15,23 +15,6 @@
# POSTGRES_PORT=5432
# POSTGRES_HOST=localhost
# =============================================================================
# TRANSCRIBE CONFIG EXAMPLE
# -----------------------------------------------------------------------------
# This service is not required, and it will be ignored by using --profile server
# when running docker-compose. If you want to use it, you need to set the
# following environment variables.
# =============================================================================
# TRANSCRIBE_API_KEY=secret_string_shared_between_server_and_transcribe
# TRANSCRIBE_ENABLED=true
# QUEUE_DATABASE_NAME=transcribe
# QUEUE_DATABASE_USER=transcribe
# QUEUE_DATABASE_PASSWORD=transcribe
# QUEUE_DATABASE_PORT=5431
# HTR_CLI_IMAGES_FOLDER=/home/user/images_storage
# =============================================================================
# DEV CONFIG EXAMPLE
# -----------------------------------------------------------------------------

View File

@@ -1,35 +0,0 @@
# =============================================================================
# Required
# -----------------------------------------------------------------------------
# =============================================================================
SERVER_PORT=4567
API_KEY=random-string
QUEUE_TTL=900000
QUEUE_RETRY_COUNT=2
QUEUE_MAINTENANCE_INTERVAL=30000
IMAGE_MAX_DIMENSION=400
HTR_CLI_DOCKER_IMAGE=joplin/htr-cli:latest
# Fullpath to images folder e.g.:
#HTR_CLI_IMAGES_FOLDER=/home/user/joplin/packages/transcribe/images
HTR_CLI_IMAGES_FOLDER=
QUEUE_DRIVER=pg
# QUEUE_DRIVER=sqlite
FILE_STORAGE_MAINTENANCE_INTERVAL=3600000
FILE_STORAGE_TTL=604800000 # one week
# =============================================================================
# Queue driver
# -----------------------------------------------------------------------------
# =============================================================================
#
# QUEUE_DATABASE_NAME=./queue.sqlite3
QUEUE_DATABASE_NAME=transcribe
QUEUE_DATABASE_USER=transcribe
QUEUE_DATABASE_PASSWORD=transcribe
QUEUE_DATABASE_PORT=5432
QUEUE_DATABASE_HOST=localhost

File diff suppressed because it is too large Load Diff

View File

@@ -23,9 +23,6 @@ module.exports = {
'FileSystemCreateWritableOptions': 'readonly',
'FileSystemHandle': 'readonly',
'IDBTransactionMode': 'readonly',
'FlatArray': 'readonly',
'BigInt': 'readonly',
'globalThis': 'readonly',
// ServiceWorker
'ExtendableEvent': 'readonly',
@@ -60,8 +57,6 @@ module.exports = {
'tinymce': 'readonly',
'JSX': 'readonly',
'NodeJS': 'readonly',
},
'parserOptions': {
'ecmaVersion': 2018,
@@ -92,7 +87,6 @@ module.exports = {
allowEmptyReject: true,
}],
'no-throw-literal': ['error'],
'no-unused-expressions': ['error'],
// This rule should not be enabled since it matters in what order
// imports are done, in particular in relation to the shim.setReact
@@ -314,7 +308,7 @@ module.exports = {
selector: 'interface',
format: null,
'filter': {
'regex': '^(RSA|RSAKeyPair|iOS.*)$',
'regex': '^(RSA|RSAKeyPair)$',
'match': true,
},
},

View File

@@ -1,8 +1,8 @@
blank_issues_enabled: true
blank_issues_enabled: false
contact_links:
- name: Feature Requests
url: https://discourse.joplinapp.org/c/features/
about: Discuss ideas for new features or changes
- name: Support
url: https://discourse.joplinapp.org/c/support/
about: Please ask for help here
about: Please ask for help here

View File

@@ -1,34 +0,0 @@
#!/bin/bash
VERSION=$(echo "$GIT_TAG_NAME" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
echo "GIT_TAG_NAME=$GIT_TAG_NAME"
echo "VERSION=$VERSION"
echo "SERVER_TAG_PREFIX=$SERVER_TAG_PREFIX"
echo "SERVER_REPOSITORY=$SERVER_REPOSITORY"
# Check if it's a server release, otherwise exit
if [[ $GIT_TAG_NAME != $SERVER_TAG_PREFIX-* ]]; then
exit 0
fi
docker manifest inspect $SERVER_REPOSITORY:arm64-$VERSION > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Image $SERVER_REPOSITORY:arm64-$VERSION does not exist on the remote registry."
exit 0
fi
docker manifest inspect $SERVER_REPOSITORY:amd64-$VERSION > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Image $SERVER_REPOSITORY:amd64-$VERSION does not exist on the remote registry."
exit 0
fi
docker manifest create $SERVER_REPOSITORY:$VERSION \
$SERVER_REPOSITORY:arm64-$VERSION \
$SERVER_REPOSITORY:amd64-$VERSION
docker manifest annotate $SERVER_REPOSITORY:$VERSION $SERVER_REPOSITORY:arm64-$VERSION --arch arm64
docker manifest annotate $SERVER_REPOSITORY:$VERSION $SERVER_REPOSITORY:amd64-$VERSION --arch amd64
docker manifest push $SERVER_REPOSITORY:$VERSION

View File

@@ -7,13 +7,9 @@
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
ROOT_DIR="$SCRIPT_DIR/../.."
TRANSCRIBE_TAG_PREFIX=transcribe
TRANSCRIBE_REPOSITORY=joplin/transcribe
IS_PULL_REQUEST=0
IS_DESKTOP_RELEASE=0
IS_SERVER_RELEASE=0
IS_TRANSCRIBE_RELEASE=0
IS_LINUX=0
IS_MACOS=0
@@ -27,10 +23,6 @@ if [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
IS_SERVER_RELEASE=1
fi
if [[ $GIT_TAG_NAME = $TRANSCRIBE_TAG_PREFIX-* ]]; then
IS_TRANSCRIBE_RELEASE=1
fi
if [[ $GIT_TAG_NAME = v* ]]; then
IS_DESKTOP_RELEASE=1
fi
@@ -43,45 +35,18 @@ else
IS_MACOS=1
fi
DOCKER_IMAGE_PLATFORM="linux/amd64"
# Tests can randomly fail in some cases, so only run them when not publishing
# a release
RUN_TESTS=0
if [ "$IS_SERVER_RELEASE" = 0 ] && [ "$IS_DESKTOP_RELEASE" = 0 ] && [ "$IS_TRANSCRIBE_RELEASE" = 0 ]; then
if [ "$IS_SERVER_RELEASE" = 0 ] && [ "$IS_DESKTOP_RELEASE" = 0 ]; then
RUN_TESTS=1
fi
if [ "$RUNNER_ARCH" == "ARM64" ]; then
if [ "$IS_SERVER_RELEASE" == "0" ] && [ "$IS_TRANSCRIBE_RELEASE" == "0" ]; then
# We exit now because nothing works properly with the ARM64 architecture.
# We only proceed if building the server image.
echo "Running on ARM64 and not trying to build server image - early exit"
exit 0
fi
fi
if [ "$RUNNER_ARCH" == "ARM64" ]; then
# Canvas is only needed for tests and it doesn't build in ARM64 so remove it
RUN_TESTS=0
cd "$ROOT_DIR/packages/lib"
yarn remove canvas
cd "$ROOT_DIR"
DOCKER_IMAGE_PLATFORM="linux/arm64"
# Delete certain directories because `yarn install` will fail on ARM64.
rm -rf app-desktop
rm -rf app-mobile
fi
# =============================================================================
# Print environment
# =============================================================================
echo "RUNNER_OS=$RUNNER_OS"
echo "RUNNER_ARCH=$RUNNER_ARCH"
echo "GITHUB_WORKFLOW=$GITHUB_WORKFLOW"
echo "GITHUB_EVENT_NAME=$GITHUB_EVENT_NAME"
echo "GITHUB_REF=$GITHUB_REF"
@@ -90,14 +55,12 @@ echo "GIT_TAG_NAME=$GIT_TAG_NAME"
echo "BUILD_SEQUENCIAL=$BUILD_SEQUENCIAL"
echo "SERVER_REPOSITORY=$SERVER_REPOSITORY"
echo "SERVER_TAG_PREFIX=$SERVER_TAG_PREFIX"
echo "TRANSCRIBE_TAG_PREFIX=$TRANSCRIBE_TAG_PREFIX"
echo "DOCKER_IMAGE_PLATFORM=$DOCKER_IMAGE_PLATFORM"
echo "PR_TITLE=$PR_TITLE"
echo "IS_CONTINUOUS_INTEGRATION=$IS_CONTINUOUS_INTEGRATION"
echo "IS_PULL_REQUEST=$IS_PULL_REQUEST"
echo "IS_DESKTOP_RELEASE=$IS_DESKTOP_RELEASE"
echo "IS_SERVER_RELEASE=$IS_SERVER_RELEASE"
echo "IS_TRANSCRIBE_RELEASE=$IS_TRANSCRIBE_RELEASE"
echo "RUN_TESTS=$RUN_TESTS"
echo "IS_LINUX=$IS_LINUX"
echo "IS_MACOS=$IS_MACOS"
@@ -119,40 +82,6 @@ if [ $testResult -ne 0 ]; then
exit $testResult
fi
# =============================================================================
# Run test units
# =============================================================================
if [ "$RUN_TESTS" == "1" ]; then
echo "Step: Running tests..."
# On Linux, we run the Joplin Server tests using PostgreSQL
if [ "$IS_LINUX" == "1" ]; then
echo "Running Joplin Server tests using PostgreSQL..."
sudo docker compose --parallel 1 --file docker-compose.db-dev.yml up -d
cmdResult=$?
if [ $cmdResult -ne 0 ]; then
exit $cmdResult
fi
export JOPLIN_TESTS_SERVER_DB=pg
else
echo "Running Joplin Server tests using SQLite..."
fi
# Need this because we're getting this error:
#
# @joplin/lib: FATAL ERROR: Ineffective mark-compacts near heap limit
# Allocation failed - JavaScript heap out of memory
#
# https://stackoverflow.com/questions/38558989
export NODE_OPTIONS="--max-old-space-size=32768"
yarn test-ci
testResult=$?
if [ $testResult -ne 0 ]; then
exit $testResult
fi
fi
# =============================================================================
# Run linter for pull requests only. We also don't want this to make the desktop
# release randomly fail.
@@ -210,6 +139,23 @@ if [ "$RUN_TESTS" == "1" ]; then
fi
fi
# =============================================================================
# Check whether this is a translation PR. There is no need to run the entire
# pipeline in such a case, thus exit early.
# =============================================================================
if [ "$RUN_TESTS" == "1" ]; then
# Due to the ancient bash release in macOS, the following is required, instead
# of using ${var,,}
PR_TITLE=$(echo $PR_TITLE |tr '[:upper:]' '[:lower:]')
echo "Step: Checking for translation PR..."
if [[ "$PR_TITLE" =~ ^.*(translation|(add|fix|update) .*language|\.po)( .*)?$ ]]; then
echo "It is a translation PR. Exit early."
exit 0
fi
fi
# =============================================================================
# Check .gitignore and .eslintignore files - they should be updated when
# new TypeScript files are added by running `yarn updateIgnored`.
@@ -223,7 +169,7 @@ if [ "$IS_LINUX" == "1" ]; then
# so that checkIgnoredFiles works.
git restore .gitignore .eslintignore
node packages/tools/checkIgnoredFiles.js
node packages/tools/checkIgnoredFiles.js
testResult=$?
if [ $testResult -ne 0 ]; then
exit $testResult
@@ -262,6 +208,40 @@ if [ "$IS_LINUX" == "1" ]; then
fi
fi
# =============================================================================
# Run test units
# =============================================================================
if [ "$RUN_TESTS" == "1" ]; then
echo "Step: Running tests..."
# On Linux, we run the Joplin Server tests using PostgreSQL
if [ "$IS_LINUX" == "1" ]; then
echo "Running Joplin Server tests using PostgreSQL..."
sudo docker compose --file docker-compose.db-dev.yml up -d
cmdResult=$?
if [ $cmdResult -ne 0 ]; then
exit $cmdResult
fi
export JOPLIN_TESTS_SERVER_DB=pg
else
echo "Running Joplin Server tests using SQLite..."
fi
# Need this because we're getting this error:
#
# @joplin/lib: FATAL ERROR: Ineffective mark-compacts near heap limit
# Allocation failed - JavaScript heap out of memory
#
# https://stackoverflow.com/questions/38558989
export NODE_OPTIONS="--max-old-space-size=32768"
yarn test-ci
testResult=$?
if [ $testResult -ne 0 ]; then
exit $testResult
fi
fi
# =============================================================================
# Find out if we should run the build or not. Electron-builder gets stuck when
# building PRs so we disable it in this case. The Linux build should provide
@@ -295,7 +275,7 @@ if [ "$IS_DESKTOP_RELEASE" == "1" ]; then
if [ "$IS_MACOS" == "1" ]; then
# This is to fix this error:
#
#
# Exit code: ENOENT. spawn /usr/bin/python ENOENT
#
# Ref: https://github.com/electron-userland/electron-builder/issues/6767#issuecomment-1096589528
@@ -311,18 +291,14 @@ if [ "$IS_DESKTOP_RELEASE" == "1" ]; then
USE_HARD_LINKS=false yarn dist
else
USE_HARD_LINKS=false yarn dist
fi
fi
elif [[ $IS_LINUX = 1 ]] && [ "$IS_SERVER_RELEASE" == "1" ]; then
echo "Step: Building Joplin Server Docker Image..."
echo "Step: Building Docker Image..."
cd "$ROOT_DIR"
yarn buildServerDocker --docker-file Dockerfile.server --platform $DOCKER_IMAGE_PLATFORM --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY
elif [[ $IS_LINUX = 1 ]] && [ "$IS_TRANSCRIBE_RELEASE" == "1" ]; then
echo "Step: Building Joplin Transcribe Docker Image..."
cd "$ROOT_DIR"
yarn buildServerDocker --docker-file Dockerfile.transcribe --platform $DOCKER_IMAGE_PLATFORM --tag-name $GIT_TAG_NAME --push-images --repository $TRANSCRIBE_REPOSITORY
yarn buildServerDocker --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY
else
echo "Step: Building but *not* publishing desktop application..."
if [ "$IS_MACOS" == "1" ]; then
# See above why we need to specify Python
alias python=$(which python3)
@@ -332,7 +308,7 @@ else
# https://www.electron.build/code-signing#how-to-disable-code-signing-during-the-build-process-on-macos
export CSC_IDENTITY_AUTO_DISCOVERY=false
npm pkg set 'build.mac.identity'=null --json
USE_HARD_LINKS=false yarn dist --publish=never
else
USE_HARD_LINKS=false yarn dist --publish=never

View File

@@ -18,7 +18,7 @@ jobs:
steps:
- id: automerge
name: automerge
uses: "pascalgn/automerge-action@v0.16.4"
uses: "pascalgn/automerge-action@v0.16.3"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
MERGE_METHOD: "squash"

View File

@@ -21,53 +21,23 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version: '24'
node-version: '18'
cache: 'yarn'
- uses: dtolnay/rust-toolchain@stable
- name: Install Yarn
run: |
corepack enable
- name: Install
run: yarn install
env:
SKIP_ONENOTE_CONVERTER_BUILD: 1
- name: Free disk space
run: |
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /opt/ghc || true
- name: Assemble Android Release
run: |
cd packages/app-mobile/android
sed -i -- 's/signingConfig signingConfigs.release/signingConfig signingConfigs.debug/' app/build.gradle
./gradlew assembleRelease
- name: Verify alignment
run: |
cd packages/app-mobile/android/app
APK_FILE="./build/outputs/apk/release/app-release.apk"
if test ! -f "$APK_FILE" ; then
echo "APK file not found."
exit 1
else
echo "APK file found at: $APK_FILE"
fi
BUILD_TOOLS_PATH="$ANDROID_HOME/build-tools/"
if test ! -d "$BUILD_TOOLS_PATH" ; then
echo "Build tools not found at $BUILD_TOOLS_PATH ($ANDROID_HOME, $BUILD_TOOLS_VERSION)"
exit 1
fi
# The build-tools/ directory contains different subdirectories
# for each build tools version. As a result, there may be multiple
# zipalign tools. Select the most recent (biggest two-digit version number):
ZIPALIGN_PATH="$(find $BUILD_TOOLS_PATH -name "zipalign" -print | sort | tail -n1)"
if test ! -x "$ZIPALIGN_PATH" ; then
echo "zipalign not found (searching in $BUILD_TOOLS_PATH, candidate: $ZIPALIGN_PATH)"
exit 1
fi
"$ZIPALIGN_PATH" -c -P 16 -v 4 "$APK_FILE"

View File

@@ -8,10 +8,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: olegtarasov/get-tag@v2.1.4
- uses: actions/setup-node@v6
- uses: olegtarasov/get-tag@v2.1.3
- uses: actions/setup-node@v4
with:
node-version: '24'
# We need to pin the version to 18.15, because 18.16+ fails with this error:
# https://github.com/facebook/react-native/issues/36440
node-version: '18.15.0'
cache: 'yarn'
- name: Install Yarn
@@ -28,7 +30,7 @@ jobs:
# See github-action-main.yml for explanation
- uses: actions/setup-python@v5
with:
python-version: '3.13'
python-version: '3.11'
- name: Set Publish Flag
run: |

View File

@@ -19,7 +19,7 @@ jobs:
# the below token should have repo scope and must be manually added by you in the repository's secret
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
path-to-signatures: 'readme/cla/signatures.json'
path-to-signatures: 'readme/cla_signatures.json'
path-to-document: 'https://github.com/laurent22/joplin/blob/dev/readme/cla.md' # e.g. a CLA or a DCO document
# branch should not be protected
branch: 'cla_signatures'

View File

@@ -9,14 +9,50 @@ jobs:
matrix:
# Do not use unbuntu-latest because it causes `The operation was canceled` failures:
# https://github.com/actions/runner-images/issues/6709
os: [macos-15-intel, ubuntu-22.04, windows-2025, ubuntu-22.04-arm]
os: [macos-13, ubuntu-20.04, windows-2019]
steps:
- uses: actions/checkout@v4
- name: Setup build environment
uses: ./.github/workflows/shared/setup-build-environment
# Trying to fix random networking issues on Windows
# https://github.com/actions/runner-images/issues/1187#issuecomment-686735760
- name: Disable TCP/UDP offload on Windows
if: runner.os == 'Windows'
run: Disable-NetAdapterChecksumOffload -Name * -TcpIPv4 -UdpIPv4 -TcpIPv6 -UdpIPv6
- name: Disable TCP/UDP offload on Linux
if: runner.os == 'Linux'
run: sudo ethtool -K eth0 tx off rx off
- name: Disable TCP/UDP offload on macOS
if: runner.os == 'macOS'
run: |
sudo sysctl -w net.link.generic.system.hwcksum_tx=0
sudo sysctl -w net.link.generic.system.hwcksum_rx=0
# Silence apt-get update errors (for example when a module doesn't
# exist) since otherwise it will make the whole build fails, even though
# it might work without update. libsecret-1-dev is required for keytar -
# https://github.com/atom/node-keytar
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update || true
sudo apt-get install -y gettext
sudo apt-get install -y libsecret-1-dev
sudo apt-get install -y translate-toolkit
sudo apt-get install -y rsync
# Provides a virtual display on Linux. Used for Playwright integration
# testing.
sudo apt-get install -y xvfb
- name: Install macOs dependencies
if: runner.os == 'macOS'
run: |
# Required for building the canvas package
brew install pango
- name: Install Docker Engine
# if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v')
if: runner.os == 'Linux'
run: |
sudo apt-get install -y apt-transport-https
@@ -26,45 +62,43 @@ jobs:
sudo apt-get install -y lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update || true
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
- name: Free disk space
if: runner.os == 'Linux'
- uses: actions/checkout@v4
- uses: olegtarasov/get-tag@v2.1.3
- uses: dtolnay/rust-toolchain@stable
- uses: actions/setup-node@v4
with:
# We need to pin the version to 18.15, because 18.16+ fails with this error:
# https://github.com/facebook/react-native/issues/36440
node-version: '18.15.0'
cache: 'yarn'
- name: Install Yarn
run: |
sudo rm -rf /usr/local/lib/android || true
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /opt/ghc || true
docker system prune -af || true
docker builder prune -af || true
sudo rm -rf /var/lib/docker/tmp/* || true
# https://yarnpkg.com/getting-started/install
corepack enable
# Login to Docker only if we're on a server release tag. If we run this on
# a pull request it will fail because the PR doesn't have access to
# secrets
- uses: docker/login-action@v3
if: runner.os == 'Linux' && (startsWith(github.ref, 'refs/tags/server-v') || startsWith(github.ref, 'refs/tags/transcribe-v'))
if: runner.os == 'Linux' && startsWith(github.ref, 'refs/tags/server-v')
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# - name: Test Windows app signing
# if: runner.os == 'Windows'
# env:
# GH_TOKEN: ${{ secrets.GH_TOKEN }}
# IS_CONTINUOUS_INTEGRATION: 1
# BUILD_SEQUENCIAL: 1
# SSL_ESIGNER_USER_NAME: ${{ secrets.SSL_ESIGNER_USER_NAME }}
# SSL_ESIGNER_USER_PASSWORD: ${{ secrets.SSL_ESIGNER_USER_PASSWORD }}
# SSL_ESIGNER_CREDENTIAL_ID: ${{ secrets.SSL_ESIGNER_CREDENTIAL_ID }}
# SSL_ESIGNER_USER_TOTP: ${{ secrets.SSL_ESIGNER_USER_TOTP }}
# SIGN_APPLICATION: 1
# # To ensure that the operations stop on failure, all commands
# # should be on one line with "&&" in between.
# run: |
# yarn install && cd packages/app-desktop && yarn dist
# macos-latest ships with Python 3.12 by default, but this removes a
# utility that's used by electron-builder (distutils) so we need to pin
# Python to an earlier version.
# Fixes error `ModuleNotFoundError: No module named 'distutils'`
# Ref: https://github.com/nodejs/node-gyp/issues/2869
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Run tests, build and publish Linux and macOS apps
if: runner.os == 'Linux' || runner.os == 'macOs'
@@ -81,20 +115,18 @@ jobs:
SERVER_REPOSITORY: joplin/server
SERVER_TAG_PREFIX: server
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
"${GITHUB_WORKSPACE}/.github/scripts/run_ci.sh"
- name: Build and publish Windows app
if: runner.os == 'Windows' && startsWith(github.ref, 'refs/tags/v')
env:
CSC_KEY_PASSWORD: ${{ secrets.WINDOWS_CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.WINDOWS_CSC_LINK }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
IS_CONTINUOUS_INTEGRATION: 1
BUILD_SEQUENCIAL: 1
SSL_ESIGNER_USER_NAME: ${{ secrets.SSL_ESIGNER_USER_NAME }}
SSL_ESIGNER_USER_PASSWORD: ${{ secrets.SSL_ESIGNER_USER_PASSWORD }}
SSL_ESIGNER_CREDENTIAL_ID: ${{ secrets.SSL_ESIGNER_CREDENTIAL_ID }}
SSL_ESIGNER_USER_TOTP: ${{ secrets.SSL_ESIGNER_USER_TOTP }}
SIGN_APPLICATION: 1
# To ensure that the operations stop on failure, all commands
# should be on one line with "&&" in between.
run: |
@@ -112,15 +144,6 @@ jobs:
run: |
yarn install && cd packages/app-desktop && yarn dist --publish=never
- name: Publish Docker manifest
if: runner.os == 'Linux'
env:
SERVER_REPOSITORY: joplin/server
SERVER_TAG_PREFIX: server
run: |
chmod 700 "${GITHUB_WORKSPACE}/.github/scripts/publish_docker_manifest.sh"
"${GITHUB_WORKSPACE}/.github/scripts/publish_docker_manifest.sh"
ServerDockerImage:
if: github.repository == 'laurent22/joplin'
runs-on: ${{ matrix.os }}
@@ -128,7 +151,7 @@ jobs:
matrix:
# Do not use unbuntu-latest because it causes `The operation was canceled` failures:
# https://github.com/actions/runner-images/issues/6709
os: [ubuntu-22.04, ubuntu-22.04-arm]
os: [ubuntu-20.04]
steps:
- name: Install Docker Engine
@@ -140,26 +163,17 @@ jobs:
sudo apt-get install -y lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update || true
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
- uses: actions/checkout@v4
- uses: actions/setup-node@v6
- uses: actions/setup-node@v4
with:
node-version: '24'
- name: Free disk space
if: runner.os == 'Linux'
run: |
sudo rm -rf /usr/local/lib/android || true
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /opt/ghc || true
docker system prune -af || true
docker builder prune -af || true
sudo rm -rf /var/lib/docker/tmp/* || true
node-version: '18'
cache: 'yarn'
- name: Install Yarn
run: |
@@ -170,48 +184,40 @@ jobs:
env:
BUILD_SEQUENCIAL: 1
run: |
if [ "$RUNNER_ARCH" == "ARM64" ]; then
DOCKER_IMAGE_PLATFORM="linux/arm64"
fi
echo "RUNNER_OS=$RUNNER_OS"
echo "RUNNER_ARCH=$RUNNER_ARCH"
echo "DOCKER_IMAGE_PLATFORM=$DOCKER_IMAGE_PLATFORM"
yarn install
yarn buildServerDocker --docker-file Dockerfile.server --platform $DOCKER_IMAGE_PLATFORM --tag-name server-v0.0.0 --repository joplin/server
yarn buildServerDocker --tag-name server-v0.0.0 --repository joplin/server
# Basic test to ensure that the created build is valid. It should exit with
# code 0 if it works.
docker run joplin/server:$(dpkg --print-architecture)-0.0.0 node dist/app.js migrate list
# code 0 if it works.
docker run joplin/server:0.0.0-beta node dist/app.js migrate list
- name: Check HTTP request
run: |
# Need to pass environment variables:
docker run --env MAX_TIME_DRIFT=0 --publish 22300:22300 joplin/server:$(dpkg --print-architecture)-0.0.0 node dist/app.js --env dev &
docker run -p 22300:22300 joplin/server:0.0.0-beta node dist/app.js --env dev &
# Wait for server to start
sleep 120
sleep 30
# Check if status code is correct
# if the actual_status DOES NOT include the expected_status
# it exits the process with code 1
expected_status="HTTP/1.1 200 OK"
actual_status=$(curl -I -X GET http://localhost:22300/api/ping | head -n 1)
if [[ ! "$actual_status" =~ "$expected_status" ]]; then
if [[ ! "$actual_status" =~ "$expected_status" ]]; then
echo 'Failed while checking the status code after request to /api/ping'
echo 'expected: ' $expected_status
echo 'actual: ' $actual_status
exit 1;
exit 1;
fi
# Check if the body response is correct
# if the actual_body is different of expected_body exit with code 1
expected_body='{"status":"ok","message":"Joplin Server is running"}'
actual_body=$(curl http://localhost:22300/api/ping)
if [[ "$actual_body" != "$expected_body" ]]; then
echo 'Failed while checking the body response after request to /api/ping'
exit 1;
fi
fi

View File

@@ -1,75 +0,0 @@
name: 'Setup build environment'
description: 'Install Joplin build dependencies'
runs:
using: 'composite'
steps:
# Trying to fix random networking issues on Windows
# https://github.com/actions/runner-images/issues/1187#issuecomment-686735760
# - name: Disable TCP/UDP offload on Windows
# if: runner.os == 'Windows'
# shell: pwsh
# run: Disable-NetAdapterChecksumOffload -Name * -TcpIPv4 -UdpIPv4 -TcpIPv6 -UdpIPv6
- name: Disable TCP/UDP offload on Linux
if: runner.os == 'Linux'
shell: bash
run: sudo ethtool -K eth0 tx off rx off
- name: Disable TCP/UDP offload on macOS
if: runner.os == 'macOS'
shell: bash
run: |
sudo sysctl -w net.link.generic.system.hwcksum_tx=0
sudo sysctl -w net.link.generic.system.hwcksum_rx=0
# Silence apt-get update errors (for example when a module doesn't
# exist) since otherwise it will make the whole build fails, even though
# it might work without update. libsecret-1-dev is required for keytar -
# https://github.com/atom/node-keytar
- name: Install Linux dependencies
if: runner.os == 'Linux'
shell: bash
run: |
sudo apt-get update || true
sudo apt-get install -y gettext
sudo apt-get install -y libsecret-1-dev
sudo apt-get install -y translate-toolkit
sudo apt-get install -y rsync
# Provides a virtual display on Linux. Used for Playwright integration
# testing.
sudo apt-get install -y xvfb
- name: Install macOs dependencies
if: runner.os == 'macOS'
shell: bash
run: |
# Required for building the canvas package
brew install pango
- uses: olegtarasov/get-tag@v2.1.4
- uses: dtolnay/rust-toolchain@stable
if: ${{ runner.os != 'Windows' }}
- uses: actions/setup-node@v6
with:
node-version: '24'
# Disable the cache on ARM runners. For now, we don't run "yarn install" on these
# environments and this breaks actions/setup-node.
# See https://github.com/laurent22/joplin/commit/47d0d3eb9e89153a609fb5441344da10904c6308#commitcomment-159577783.
# cache: ${{ (!contains(runner.os, 'arm') && 'yarn') || '' }}
- name: Install Yarn
shell: bash
run: |
# https://yarnpkg.com/getting-started/install
corepack enable
# macos-latest ships with Python 3.12 by default, but this removes a
# utility that's used by electron-builder (distutils) so we need to pin
# Python to an earlier version.
# Fixes error `ModuleNotFoundError: No module named 'distutils'`
# Ref: https://github.com/nodejs/node-gyp/issues/2869
- uses: actions/setup-python@v5
with:
python-version: '3.13'

View File

@@ -1,35 +0,0 @@
name: Joplin UI tests
on: [push, pull_request]
permissions:
contents: read
jobs:
Main:
# Don't run on forks
if: github.repository == 'laurent22/joplin'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04, windows-2025]
steps:
- uses: actions/checkout@v4
- name: Setup build environment
uses: ./.github/workflows/shared/setup-build-environment
- name: Build
run: yarn install
env:
# The onenote-converter package uses Rust, which isn't installed on all CI
# runners. Since the onenote-converter doesn't have UI tests, it can be excluded
# from build:
SKIP_ONENOTE_CONVERTER_BUILD: 1
- name: Run UI tests
shell: bash
run: |
cd ${GITHUB_WORKSPACE}/packages/app-desktop/
bash ./integration-tests/run-ci.sh
# See https://playwright.dev/docs/ci-intro#setting-up-github-actions
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report-${{ matrix.os }}
path: packages/app-desktop/playwright-report/
retention-days: 7

508
.gitignore vendored

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
corepack yarn lint-staged

View File

@@ -3,24 +3,23 @@
"prefer-absolute-version-dependencies": ["error",
{
"exceptions": [
"@joplin/lib",
"@joplin/renderer",
"@joplin/editor",
"@joplin/pdf-viewer",
"@joplin/fork-htmlparser2",
"@joplin/fork-sax",
"@joplin/fork-uslug",
"@joplin/htmlpack",
"@joplin/transcribe",
"@joplin/lib",
"@joplin/onenote-converter",
"@joplin/pdf-viewer",
"@joplin/react-native-alarm-notification",
"@joplin/react-native-saf-x",
"@joplin/renderer",
"@joplin/tools",
"@joplin/turndown-plugin-gfm",
"@joplin/turndown",
"@joplin/turndown-plugin-gfm",
"@joplin/tools",
"@joplin/react-native-saf-x",
"@joplin/react-native-alarm-notification",
"@joplin/utils"
]
}
]
}
}

View File

@@ -1,4 +1,3 @@
{
"cSpell.enabled": true,
"editor.insertSpaces": false
"cSpell.enabled": true
}

View File

@@ -1,10 +0,0 @@
# @joplin/empty
An empty package. This package can be used to exclude certain dependencies from build.
For example, the `canvas` dependency is an optional dependency of `pdfjs-dist`. However, it isn't used by Joplin and can cause build to fail in certain environments. The `@joplin/empty` package can exclude `canvas` from the build by adding a resolution to `resolutions` in the top-level `package.json`. For example, resolving `canvas@npm:^2.11` to `file:./packages/empty/`.
See also:
- [Yarn docs: Manifest resolutions](https://yarnpkg.com/configuration/manifest#resolutions)
- [GitHub comment: Yarn: Ignoring packages](https://github.com/yarnpkg/yarn/issues/4611#issuecomment-1370284462)

View File

@@ -1,10 +0,0 @@
{
"name": "@joplin/empty",
"version": "0.0.0",
"description": "An empty package, used as a way to exclude certain packages from build",
"private": true,
"repository": {
"type": "git",
"url": "git+https://github.com/laurent22/joplin.git"
}
}

View File

@@ -0,0 +1,62 @@
diff --git a/android/src/newarch/java/com/reactnativecommunity/slider/ReactSliderManager.java b/android/src/newarch/java/com/reactnativecommunity/slider/ReactSliderManager.java
index a5bb95eec3337b93a2338a2869a2bda176c91cae..87817688eb280c2f702c26dc35558c6a0a4db1ea 100644
--- a/android/src/newarch/java/com/reactnativecommunity/slider/ReactSliderManager.java
+++ b/android/src/newarch/java/com/reactnativecommunity/slider/ReactSliderManager.java
@@ -42,12 +42,20 @@ public class ReactSliderManager extends SimpleViewManager<ReactSlider> implement
public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) {
ReactSlider slider = (ReactSlider)seekbar;
- if(progress < slider.getLowerLimit()) {
- progress = slider.getLowerLimit();
- seekbar.setProgress(progress);
- } else if (progress > slider.getUpperLimit()) {
- progress = slider.getUpperLimit();
- seekbar.setProgress(progress);
+ // During initialization, lowerLimit can be greater than upperLimit.
+ //
+ // If a change event is received during this, we need a check to prevent
+ // infinite recursion.
+ //
+ // Issue: https://github.com/callstack/react-native-slider/issues/571
+ if (slider.getLowerLimit() <= slider.getUpperLimit()) {
+ if(progress < slider.getLowerLimit()) {
+ progress = slider.getLowerLimit();
+ seekbar.setProgress(progress);
+ } else if (progress > slider.getUpperLimit()) {
+ progress = slider.getUpperLimit();
+ seekbar.setProgress(progress);
+ }
}
ReactContext reactContext = (ReactContext) seekbar.getContext();
diff --git a/android/src/oldarch/java/com/reactnativecommunity/slider/ReactSliderManager.java b/android/src/oldarch/java/com/reactnativecommunity/slider/ReactSliderManager.java
index 3ff5930f85a3cd92c2549925f41058abb188a57e..ab3681fdfe0b736c97020e1434e450c8183e6f18 100644
--- a/android/src/oldarch/java/com/reactnativecommunity/slider/ReactSliderManager.java
+++ b/android/src/oldarch/java/com/reactnativecommunity/slider/ReactSliderManager.java
@@ -30,12 +30,20 @@ public class ReactSliderManager extends SimpleViewManager<ReactSlider> {
public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) {
ReactSlider slider = (ReactSlider)seekbar;
- if(progress < slider.getLowerLimit()) {
- progress = slider.getLowerLimit();
- seekbar.setProgress(progress);
- } else if(progress > slider.getUpperLimit()) {
- progress = slider.getUpperLimit();
- seekbar.setProgress(progress);
+ // During initialization, lowerLimit can be greater than upperLimit.
+ //
+ // If a change event is received during this, we need a check to prevent
+ // infinite recursion.
+ //
+ // Issue: https://github.com/callstack/react-native-slider/issues/571
+ if (slider.getLowerLimit() <= slider.getUpperLimit()) {
+ if(progress < slider.getLowerLimit()) {
+ progress = slider.getLowerLimit();
+ seekbar.setProgress(progress);
+ } else if (progress > slider.getUpperLimit()) {
+ progress = slider.getUpperLimit();
+ seekbar.setProgress(progress);
+ }
}
ReactContext reactContext = (ReactContext) seekbar.getContext();

View File

@@ -1,90 +0,0 @@
# This patch's goal is to work around an issue in the NSIS uninstaller on Windows:
# - For future uninstallers, this patch backports an upstream commit that changes how
# running copies of the app are found.
# - See https://github.com/electron-userland/electron-builder/pull/8133
# - If an existing uninstaller fails, gives an option to continue with the installation
# despite the failure.
# - Updates "uninstall failed" error messages to state that uninstallation failed (rather
# than incorrectly stating that the issue was with closing the app).
#
# See https://github.com/laurent22/joplin/pull/11541
diff --git a/templates/nsis/include/allowOnlyOneInstallerInstance.nsh b/templates/nsis/include/allowOnlyOneInstallerInstance.nsh
index fe5d45c730f36c9fe8d8cfea12e242e501b67139..97b27fce6798e30e3e631221435f09b3579e77c3 100644
--- a/templates/nsis/include/allowOnlyOneInstallerInstance.nsh
+++ b/templates/nsis/include/allowOnlyOneInstallerInstance.nsh
@@ -42,7 +42,7 @@
${nsProcess::FindProcess} "${_FILE}" ${_ERR}
!else
# find process owned by current user
- nsExec::Exec `%SYSTEMROOT%\System32\cmd.exe /c tasklist /FI "USERNAME eq %USERNAME%" /FI "IMAGENAME eq ${_FILE}" /FO csv | %SYSTEMROOT%\System32\find.exe "${_FILE}"`
+ nsExec::Exec `"$SYSDIR\cmd.exe" /c tasklist /FI "USERNAME eq %USERNAME%" /FI "IMAGENAME eq ${_FILE}" /FO csv | "$SYSDIR\find.exe" "${_FILE}"`
Pop ${_ERR}
!endif
!macroend
@@ -73,7 +73,7 @@
!ifdef INSTALL_MODE_PER_ALL_USERS
nsExec::Exec `taskkill /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid"`
!else
- nsExec::Exec `%SYSTEMROOT%\System32\cmd.exe /c taskkill /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"`
+ nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"`
!endif
# to ensure that files are not "in-use"
Sleep 300
@@ -91,7 +91,7 @@
!ifdef INSTALL_MODE_PER_ALL_USERS
nsExec::Exec `taskkill /f /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid"`
!else
- nsExec::Exec `%SYSTEMROOT%\System32\cmd.exe /c taskkill /f /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"`
+ nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /f /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"`
!endif
!insertmacro FIND_PROCESS "${APP_EXECUTABLE_FILENAME}" $R0
${If} $R0 == 0
diff --git a/templates/nsis/include/installUtil.nsh b/templates/nsis/include/installUtil.nsh
index 47367741632726ba0886ac516461dbe98b7aea58..675965762375925a505ca6d8bbb67507ef696c2e 100644
--- a/templates/nsis/include/installUtil.nsh
+++ b/templates/nsis/include/installUtil.nsh
@@ -126,10 +126,11 @@ Function handleUninstallResult
Return
${if} $R0 != 0
- MessageBox MB_OK|MB_ICONEXCLAMATION "$(uninstallFailed): $R0"
+ # MessageBox MB_OK|MB_ICONEXCLAMATION "$(uninstallFailed): $R0"
DetailPrint `Uninstall was not successful. Uninstaller error code: $R0.`
- SetErrorLevel 2
- Quit
+ DetailPrint `Continuing anyway. See https://github.com/laurent22/joplin/pull/11612.`
+ # SetErrorLevel 2
+ # Quit
${endif}
FunctionEnd
@@ -216,11 +217,13 @@ Function uninstallOldVersion
IntOp $R5 $R5 + 1
${if} $R5 > 5
- MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "$(appCannotBeClosed)" /SD IDCANCEL IDRETRY OneMoreAttempt
- Return
+ MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "$(appCannotBeUninstalled)" /SD IDCANCEL IDRETRY ContinueWithoutUninstall
+ Abort ; Exit early
+ ContinueWithoutUninstall:
+ Return
${endIf}
- OneMoreAttempt:
+# OneMoreAttempt: ; Commented out because unused
ExecWait '"$uninstallerFileNameTemp" /S /KEEP_APP_DATA $0 _?=$installationDir' $R0
ifErrors TryInPlace CheckResult
diff --git a/templates/nsis/messages.yml b/templates/nsis/messages.yml
index a1c2847fa48d79f835b30b48e999ccaf3c818657..6884c18d1e77dbd6be114401d23cf5caf3e0dd94 100644
--- a/templates/nsis/messages.yml
+++ b/templates/nsis/messages.yml
@@ -235,3 +235,8 @@ uninstallFailed:
sv: Det gick inte att avinstallera gamla programfiler. Försök att köra installationsprogrammet igen.
uk: Не вдалось видалити старі файли застосунку. Будь ласка, спробуйте запустити встановлювач знов.
zh_TW: 無法俺安裝舊的應用程式檔案。 請嘗試再次執行安裝程式。
+
+
+appCannotBeUninstalled:
+ en: "The old version of ${PRODUCT_NAME} could not be removed. \nClick Retry to skip this step."
+

View File

@@ -0,0 +1,13 @@
diff --git a/templates/nsis/include/allowOnlyOneInstallerInstance.nsh b/templates/nsis/include/allowOnlyOneInstallerInstance.nsh
index a1fd1875d852ff69c087a3103eff827c20d37ca5..5222614ddad3276876857e7a9dde4017a6b9fc85 100644
--- a/templates/nsis/include/allowOnlyOneInstallerInstance.nsh
+++ b/templates/nsis/include/allowOnlyOneInstallerInstance.nsh
@@ -42,7 +42,7 @@
${nsProcess::FindProcess} "${_FILE}" ${_ERR}
!else
# find process owned by current user
- nsExec::Exec `cmd /c tasklist /FI "USERNAME eq %USERNAME%" /FI "IMAGENAME eq ${_FILE}" | %SYSTEMROOT%\System32\find.exe "${_FILE}"`
+ nsExec::Exec `cmd /c tasklist /FI "USERNAME eq %USERNAME%" /FI "PID ne $pid" /FI "IMAGENAME eq ${_FILE}" | %SYSTEMROOT%\System32\find.exe "${_FILE}"`
Pop ${_ERR}
!endif
!macroend

View File

@@ -1,36 +0,0 @@
# Patch to remove eval. This allows using depd in an environment with
# a strict Content-Security-Policy.
# Ref: https://github.com/dougwilson/nodejs-depd/pull/33
diff --git a/index.js b/index.js
index d758d3c8f58a60bf27ef377ad77639bf10ce7854..2bad40d4eeba553d3bcfb206873eac059067ae3b 100644
--- a/index.js
+++ b/index.js
@@ -399,19 +399,20 @@ function wrapfunction (fn, message) {
throw new TypeError('argument fn must be a function')
}
- var args = createArgumentsString(fn.length)
- var deprecate = this // eslint-disable-line no-unused-vars
var stack = getStack()
var site = callSiteLocation(stack[1])
site.name = fn.name
- // eslint-disable-next-line no-eval
- var deprecatedfn = eval('(function (' + args + ') {\n' +
- '"use strict"\n' +
- 'log.call(deprecate, message, site)\n' +
- 'return fn.apply(this, arguments)\n' +
- '})')
+ var deprecatedfn
+ var self = this
+ deprecatedfn = function () {
+ 'use strict'
+ log.call(self, message, site)
+ return fn.apply(this, arguments)
+ }
+ Object.defineProperty(deprecatedfn, 'length', { value: fn.length })
+ Object.defineProperty(deprecatedfn, 'name', { value: fn.name })
return deprecatedfn
}

View File

@@ -1,35 +0,0 @@
# Patch to remove eval. This allows using depd in an environment with
# a strict Content-Security-Policy.
# Ref: https://github.com/dougwilson/nodejs-depd/pull/33
diff --git a/index.js b/index.js
index 1bf2fcfdeffc984e5ad792eec08744c29d4a4590..1b24aa2414458bc651abfdded81b103c131efeaa 100644
--- a/index.js
+++ b/index.js
@@ -415,19 +415,19 @@ function wrapfunction (fn, message) {
throw new TypeError('argument fn must be a function')
}
- var args = createArgumentsString(fn.length)
var stack = getStack()
var site = callSiteLocation(stack[1])
site.name = fn.name
- // eslint-disable-next-line no-new-func
- var deprecatedfn = new Function('fn', 'log', 'deprecate', 'message', 'site',
- '"use strict"\n' +
- 'return function (' + args + ') {' +
- 'log.call(deprecate, message, site)\n' +
- 'return fn.apply(this, arguments)\n' +
- '}')(fn, log, this, message, site)
+ var self = this
+ var deprecatedfn = function () {
+ 'use strict'
+ log.call(self, message, site)
+ return fn.apply(this, arguments)
+ }
+ Object.defineProperty(deprecatedfn, 'length', { value: fn.length })
+ Object.defineProperty(deprecatedfn, 'name', { value: fn.name })
return deprecatedfn
}

View File

@@ -0,0 +1,33 @@
diff --git a/lib/runner/index.js b/lib/runner/index.js
index 87e3b3957619728e3ed1ca61e2d83df1c49f928f..6d5ab905415da0577341c8f5b67d4806adcf7549 100644
--- a/lib/runner/index.js
+++ b/lib/runner/index.js
@@ -68,15 +68,19 @@ function run([, scriptPath, hookName = '', HUSKY_GIT_PARAMS], getStdinFn = get_s
return 0;
}
catch (err) {
- const noVerifyMessage = [
- 'commit-msg',
- 'pre-commit',
- 'pre-rebase',
- 'pre-push'
- ].includes(hookName)
- ? '(add --no-verify to bypass)'
- : '(cannot be bypassed with --no-verify due to Git specs)';
- console.log(`husky > ${hookName} hook failed ${noVerifyMessage}`);
+ // We do not want to print this "add --no-verify to bypass" message because that's
+ // literally what some developers do instead of trying to fix the errors.
+
+ // const noVerifyMessage = [
+ // 'commit-msg',
+ // 'pre-commit',
+ // 'pre-rebase',
+ // 'pre-push'
+ // ].includes(hookName)
+ // ? '(add --no-verify to bypass)'
+ // : '(cannot be bypassed with --no-verify due to Git specs)';
+
+ console.log(`husky > ${hookName} hook failed (Please fix the errors listed above and try again)`);
return err.code;
}
});

View File

@@ -1,22 +1,6 @@
# We remove the `canvas` optional dependency because electron-rebuild fails to build it, and
# the `canvas` API is already part of Electron
diff --git a/build/pdf.js b/build/pdf.js
index 4acf16b1d6f9351bda1a98649ea4f926618fe617..f63dbc6050ca63ca8e8ed982edea134103fa15dd 100644
--- a/build/pdf.js
+++ b/build/pdf.js
@@ -6244,8 +6244,9 @@ class NodeFilterFactory extends _base_factory.BaseFilterFactory {}
exports.NodeFilterFactory = NodeFilterFactory;
class NodeCanvasFactory extends _base_factory.BaseCanvasFactory {
_createCanvas(width, height) {
- const Canvas = require("canvas");
- return Canvas.createCanvas(width, height);
+ throw new Error('Node canvas disabled');
+ // const Canvas = require("canvas");
+ // return Canvas.createCanvas(width, height);
}
}
exports.NodeCanvasFactory = NodeCanvasFactory;
diff --git a/package.json b/package.json
index 105811f53d508486e08a60dc1b6e437cd24d7427..dea6a4e6612c4a4006cc482e46ff5270dcfda1e5 100644
--- a/package.json

View File

@@ -0,0 +1,25 @@
diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
index 8a719ca35af1cc3a4192c5c5f8258fd4f7fea990..5f8831f81cd164a4f627423427ead92fa286b115 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
@@ -37,7 +37,7 @@ import com.facebook.react.uimanager.common.ViewUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -149,7 +149,10 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
}
private class ConcurrentOperationQueue {
- private final Queue<UIThreadOperation> mQueue = new ConcurrentLinkedQueue<>();
+ // Patch: Use LinkedBlockingQueue instead of ConcurrentLinkedQueue.
+ // In some versions of Android, ConcurrentLinkedQueue is known to drop
+ // items, causing crashing. See https://github.com/laurent22/joplin/issues/8425
+ private final Queue<UIThreadOperation> mQueue = new LinkedBlockingQueue<>();
@Nullable private UIThreadOperation mPeekedOperation = null;
@AnyThread

View File

@@ -1,205 +0,0 @@
# This patch fixes two issues:
# - Updates RCTDeviceInfo.m to match https://github.com/facebook/react-native/commit/0b8db7e5e814cfbf9974cc5b6ceb64e8006d8a3c.
# This fixes an issue in which useWindowDimensions returns incorrect
# values in landscape mode in iOS.
# This should be fixed in React Native 0.80. See https://github.com/facebook/react-native/issues/51086.
# - Updates NativeAnimatedModule.java to work around an Android 12-specific crash.
diff --git a/React/CoreModules/RCTDeviceInfo.mm b/React/CoreModules/RCTDeviceInfo.mm
index 6b4fcef852252e8d4ac2aceb12175fdfafb4def7..8ceab21e8653d429876d10e2d12ed1342780ad7d 100644
--- a/React/CoreModules/RCTDeviceInfo.mm
+++ b/React/CoreModules/RCTDeviceInfo.mm
@@ -14,9 +14,7 @@
#import <React/RCTEventDispatcherProtocol.h>
#import <React/RCTInitializing.h>
#import <React/RCTInvalidating.h>
-#import <React/RCTKeyWindowValuesProxy.h>
#import <React/RCTUtils.h>
-#import <React/RCTWindowSafeAreaProxy.h>
#import <atomic>
#import "CoreModulesPlugins.h"
@@ -31,8 +29,13 @@ using namespace facebook::react;
NSDictionary *_currentInterfaceDimensions;
BOOL _isFullscreen;
std::atomic<BOOL> _invalidated;
+ NSDictionary *_constants;
+
+ __weak UIWindow *_applicationWindow;
}
+static NSString *const kFrameKeyPath = @"frame";
+
@synthesize moduleRegistry = _moduleRegistry;
RCT_EXPORT_MODULE()
@@ -40,14 +43,26 @@ RCT_EXPORT_MODULE()
- (instancetype)init
{
if (self = [super init]) {
- [[RCTKeyWindowValuesProxy sharedInstance] startObservingWindowSizeIfNecessary];
+ _applicationWindow = RCTKeyWindow();
+ [_applicationWindow addObserver:self forKeyPath:kFrameKeyPath options:NSKeyValueObservingOptionNew context:nil];
}
return self;
}
+- (void)observeValueForKeyPath:(NSString *)keyPath
+ ofObject:(id)object
+ change:(NSDictionary *)change
+ context:(void *)context
+{
+ if ([keyPath isEqualToString:kFrameKeyPath]) {
+ [self interfaceFrameDidChange];
+ [[NSNotificationCenter defaultCenter] postNotificationName:RCTWindowFrameDidChangeNotification object:self];
+ }
+}
+
+ (BOOL)requiresMainQueueSetup
{
- return NO;
+ return YES;
}
- (dispatch_queue_t)methodQueue
@@ -81,7 +96,7 @@ RCT_EXPORT_MODULE()
#if TARGET_OS_IOS
- _currentInterfaceOrientation = [RCTKeyWindowValuesProxy sharedInstance].currentInterfaceOrientation;
+ _currentInterfaceOrientation = RCTKeyWindow().windowScene.interfaceOrientation;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(interfaceFrameDidChange)
@@ -98,6 +113,15 @@ RCT_EXPORT_MODULE()
selector:@selector(invalidate)
name:RCTBridgeWillInvalidateModulesNotification
object:nil];
+
+ _constants = @{
+ @"Dimensions" : [self _exportedDimensions],
+ // Note:
+ // This prop is deprecated and will be removed in a future release.
+ // Please use this only for a quick and temporary solution.
+ // Use <SafeAreaView> instead.
+ @"isIPhoneX_deprecated" : @(RCTIsIPhoneNotched()),
+ };
}
- (void)invalidate
@@ -120,6 +144,8 @@ RCT_EXPORT_MODULE()
[[NSNotificationCenter defaultCenter] removeObserver:self name:RCTBridgeWillInvalidateModulesNotification object:nil];
+ [_applicationWindow removeObserver:self forKeyPath:kFrameKeyPath];
+
#if TARGET_OS_IOS
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
#endif
@@ -132,8 +158,13 @@ static BOOL RCTIsIPhoneNotched()
#if TARGET_OS_IOS
dispatch_once(&onceToken, ^{
+ RCTAssertMainQueue();
+
// 20pt is the top safeArea value in non-notched devices
- isIPhoneNotched = [RCTWindowSafeAreaProxy sharedInstance].currentSafeAreaInsets.top > 20;
+ UIWindow *keyWindow = RCTKeyWindow();
+ if (keyWindow) {
+ isIPhoneNotched = keyWindow.safeAreaInsets.top > 20;
+ }
});
#endif
@@ -142,11 +173,13 @@ static BOOL RCTIsIPhoneNotched()
static NSDictionary *RCTExportedDimensions(CGFloat fontScale)
{
+ RCTAssertMainQueue();
UIScreen *mainScreen = UIScreen.mainScreen;
CGSize screenSize = mainScreen.bounds.size;
+ UIView *mainWindow = RCTKeyWindow();
// We fallback to screen size if a key window is not found.
- CGSize windowSize = [RCTKeyWindowValuesProxy sharedInstance].windowSize;
+ CGSize windowSize = mainWindow ? mainWindow.bounds.size : screenSize;
NSDictionary<NSString *, NSNumber *> *dimsWindow = @{
@"width" : @(windowSize.width),
@@ -170,7 +203,10 @@ static NSDictionary *RCTExportedDimensions(CGFloat fontScale)
RCTAssert(_moduleRegistry, @"Failed to get exported dimensions: RCTModuleRegistry is nil");
RCTAccessibilityManager *accessibilityManager =
(RCTAccessibilityManager *)[_moduleRegistry moduleForName:"AccessibilityManager"];
- RCTAssert(accessibilityManager, @"Failed to get exported dimensions: AccessibilityManager is nil");
+ // TOOD(T225745315): For some reason, accessibilityManager is nil in some cases.
+ // We default the fontScale to 1.0 in this case. This should be okay: if we assume
+ // that accessibilityManager will eventually become available, js will eventually
+ // be updated with the correct fontScale.
CGFloat fontScale = accessibilityManager ? accessibilityManager.multiplier : 1.0;
return RCTExportedDimensions(fontScale);
}
@@ -182,14 +218,7 @@ static NSDictionary *RCTExportedDimensions(CGFloat fontScale)
- (NSDictionary<NSString *, id> *)getConstants
{
- return @{
- @"Dimensions" : [self _exportedDimensions],
- // Note:
- // This prop is deprecated and will be removed in a future release.
- // Please use this only for a quick and temporary solution.
- // Use <SafeAreaView> instead.
- @"isIPhoneX_deprecated" : @(RCTIsIPhoneNotched()),
- };
+ return _constants;
}
- (void)didReceiveNewContentSizeMultiplier
@@ -209,10 +238,11 @@ static NSDictionary *RCTExportedDimensions(CGFloat fontScale)
- (void)interfaceOrientationDidChange
{
#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST
- UIWindow *keyWindow = RCTKeyWindow();
- UIInterfaceOrientation nextOrientation = keyWindow.windowScene.interfaceOrientation;
+ UIApplication *application = RCTSharedApplication();
+ UIInterfaceOrientation nextOrientation = RCTKeyWindow().windowScene.interfaceOrientation;
- BOOL isRunningInFullScreen = CGRectEqualToRect(keyWindow.frame, keyWindow.screen.bounds);
+ BOOL isRunningInFullScreen =
+ CGRectEqualToRect(application.delegate.window.frame, application.delegate.window.screen.bounds);
// We are catching here two situations for multitasking view:
// a) The app is in Split View and the container gets resized -> !isRunningInFullScreen
// b) The app changes to/from fullscreen example: App runs in slide over mode and goes into fullscreen->
@@ -276,3 +306,4 @@ Class RCTDeviceInfoCls(void)
{
return RCTDeviceInfo.class;
}
+
diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
index cf14e51cf5f561b84f1b6ace8410fc77d626758e..abc8c64adf26fbf73429aee7fd4f76877e98849a 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.java
@@ -42,6 +42,7 @@ import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -155,8 +156,15 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
}
private class ConcurrentOperationQueue {
- private final Queue<UIThreadOperation> mQueue = new ConcurrentLinkedQueue<>();
- @Nullable private UIThreadOperation mPeekedOperation = null;
+ // Patch: Use LinkedBlockingQueue instead of ConcurrentLinkedQueue.
+ // In some versions of Android, ConcurrentLinkedQueue is known to drop
+ // items, causing crashing. See https://github.com/laurent22/joplin/issues/8425
+ private final Queue<UIThreadOperation> mQueue = (
+ // The issue exists for Android 12, which corresponds to API levels 31 and 32.
+ Build.VERSION.SDK_INT == 31 || Build.VERSION.SDK_INT == 32
+ ) ? new LinkedBlockingQueue<>() : new ConcurrentLinkedQueue<>();
+
+ @Nullable private UIThreadOperation mPeekedOperation = null;
@AnyThread
boolean isEmpty() {

View File

@@ -1,50 +0,0 @@
# This is a (hopefully temporary) fix for an accessibility issue in the FAB.Group
# component. See https://github.com/callstack/react-native-paper/pull/4498 for details.
diff --git a/lib/commonjs/components/FAB/FABGroup.js b/lib/commonjs/components/FAB/FABGroup.js
index 26933dd7ac6862c0dd95e52b8cd91c8bbd0b6efc..417c91a0257849eb597afb5e339e13b6d1d54486 100644
--- a/lib/commonjs/components/FAB/FABGroup.js
+++ b/lib/commonjs/components/FAB/FABGroup.js
@@ -209,8 +209,9 @@ const FABGroup = _ref => {
}],
pointerEvents: open ? 'box-none' : 'none',
accessibilityRole: "button",
- importantForAccessibility: "yes",
- accessible: true,
+ importantForAccessibility: open ? 'yes' : 'no-hide-descendants',
+ accessibilityElementsHidden: !open,
+ accessible: open,
accessibilityLabel: accessibilityLabel
}, it.label && /*#__PURE__*/React.createElement(_reactNative.View, null, /*#__PURE__*/React.createElement(_Card.default, {
mode: isV3 ? 'contained' : 'elevated',
diff --git a/lib/module/components/FAB/FABGroup.js b/lib/module/components/FAB/FABGroup.js
index ca5c02679539b17b048d4c82f570791dd8b57545..a06902b744b3bfb06b0644930eda0ba2ce2967ca 100644
--- a/lib/module/components/FAB/FABGroup.js
+++ b/lib/module/components/FAB/FABGroup.js
@@ -200,8 +200,9 @@ const FABGroup = _ref => {
}],
pointerEvents: open ? 'box-none' : 'none',
accessibilityRole: "button",
- importantForAccessibility: "yes",
- accessible: true,
+ importantForAccessibility: open ? 'yes' : 'no-hide-descendants',
+ accessibilityElementsHidden: !open,
+ accessible: open,
accessibilityLabel: accessibilityLabel
}, it.label && /*#__PURE__*/React.createElement(View, null, /*#__PURE__*/React.createElement(Card, {
mode: isV3 ? 'contained' : 'elevated',
diff --git a/src/components/FAB/FABGroup.tsx b/src/components/FAB/FABGroup.tsx
index af1e85c4cbabfdd05499f9befb9f851be5911835..d010393975b0b31852efba1b7ce9cb09da4feaec 100644
--- a/src/components/FAB/FABGroup.tsx
+++ b/src/components/FAB/FABGroup.tsx
@@ -383,8 +383,9 @@ const FABGroup = ({
]}
pointerEvents={open ? 'box-none' : 'none'}
accessibilityRole="button"
- importantForAccessibility="yes"
- accessible={true}
+ importantForAccessibility={open ? 'yes' : 'no-hide-descendants'}
+ accessibilityElementsHidden={!open}
+ accessible={open}
accessibilityLabel={accessibilityLabel}
>
{it.label && (

View File

@@ -1,64 +0,0 @@
# This patch improves the note actions menu (the kebab menu)'s accessibility
# by labelling its dismiss button.
diff --git a/build/rnpm.js b/build/rnpm.js
index 47bc91a88b9e2246a0ce4295f9f932da6a572461..75b5a22bdcbc2594238bcf953df6d54e18cc7793 100644
--- a/build/rnpm.js
+++ b/build/rnpm.js
@@ -1267,7 +1267,9 @@
onPress = _this$props.onPress,
style = _this$props.style;
return React__default.createElement(reactNative.TouchableWithoutFeedback, {
- onPress: onPress
+ onPress: onPress,
+ accessibilityLabel: _this$props.accessibilityLabel,
+ accessibilityRole: 'button',
}, React__default.createElement(reactNative.Animated.View, {
style: [styles.fullscreen, {
opacity: this.fadeAnim
@@ -1282,7 +1284,8 @@
}(React.Component);
Backdrop.propTypes = {
- onPress: propTypes.func.isRequired
+ onPress: propTypes.func.isRequired,
+ accessibilityLabel: propTypes.string,
};
var styles = reactNative.StyleSheet.create({
fullscreen: {
@@ -1352,6 +1355,7 @@
style: styles$1.placeholder
}, React__default.createElement(Backdrop, {
onPress: ctx._onBackdropPress,
+ accessibilityLabel: this.props.closeButtonLabel,
style: backdropStyles,
ref: ctx.onBackdropRef
}), ctx._makeOptions());
@@ -1784,6 +1788,7 @@
}), React__default.createElement(MenuPlaceholder, {
ctx: this,
backdropStyles: customStyles.backdrop,
+ closeButtonLabel: this.props.closeButtonLabel,
ref: this._onPlaceholderRef
}))));
}
@@ -1854,7 +1859,7 @@
var _options$props = options.props,
optionsContainerStyle = _options$props.optionsContainerStyle,
renderOptionsContainer = _options$props.renderOptionsContainer,
- customStyles = _options$props.customStyles;
+ customStyles = _options$props.customStyles || {};
var optionsRenderer = renderOptionsContainer || defaultOptionsContainerRenderer;
var isOutside = !triggerLayout || !optionsLayout;
diff --git a/src/index.d.ts b/src/index.d.ts
index 7e1ef2e441a665e97c304984080399f9646395df..673c4f713757abfb1851cba0d4560020c83e5f50 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -18,6 +18,7 @@ declare module "react-native-popup-menu" {
menuProviderWrapper?: StyleProp<ViewStyle>;
backdrop?: StyleProp<ViewStyle>;
};
+ closeButtonLabel: string;
backHandler?: boolean | Function;
skipInstanceCheck?: boolean;
children: React.ReactNode;

View File

@@ -1,37 +0,0 @@
diff --git a/platforms/android/src/main/java/org/pgsqlite/SQLitePlugin.java b/platforms/android/src/main/java/org/pgsqlite/SQLitePlugin.java
index 4f2391b..f7cc433 100644
--- a/platforms/android/src/main/java/org/pgsqlite/SQLitePlugin.java
+++ b/platforms/android/src/main/java/org/pgsqlite/SQLitePlugin.java
@@ -8,11 +8,14 @@
package org.pgsqlite;
import android.annotation.SuppressLint;
+import android.database.AbstractWindowedCursor;
import android.database.Cursor;
+import android.database.CursorWindow;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteStatement;
import android.content.Context;
+import android.os.Build;
import android.util.Base64;
import java.io.Closeable;
@@ -808,6 +811,17 @@ public class SQLitePlugin extends ReactContextBaseJavaModule {
throw ex;
}
+ // To try to fix the error "Row too big to fit into CursorWindow" when using sqlite binary bundled with the device
+ // https://github.com/andpor/react-native-sqlite-storage/issues/364#issuecomment-526423153
+ // https://github.com/laurent22/joplin/issues/1767#issuecomment-515617991
+
+ if (cur != null && Build.VERSION.SDK_INT >= 28) {
+ CursorWindow cw = new CursorWindow(null, 50 * 1024 * 1024);
+ AbstractWindowedCursor ac = (AbstractWindowedCursor) cur;
+ ac.setWindow(cw);
+ cur = ac;
+ }
+
// If query result has rows
if (cur != null && cur.moveToFirst()) {
WritableArray rowsArrayResult = Arguments.createArray();

View File

@@ -0,0 +1,209 @@
diff --git a/android/build.gradle b/android/build.gradle
index 6afcbbf0cc8ca2d69dd78077d61e59a90b2136bb..9f8d72b4ec5b2b3d290975d6a255917c95300854 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -67,19 +67,19 @@ repositories {
}
// Generate UUIDs for each models contained in android/src/main/assets/
-tasks.register('genUUID') {
- doLast {
- fileTree(dir: "$rootDir/app/src/main/assets", exclude: ['*/*']).visit { fileDetails ->
- if (fileDetails.directory) {
- def odir = file("$rootDir/app/src/main/assets/$fileDetails.relativePath")
- def ofile = file("$odir/uuid")
- mkdir odir
- ofile.text = UUID.randomUUID().toString()
- }
- }
- }
-}
-preBuild.dependsOn genUUID
+// tasks.register('genUUID') {
+// doLast {
+// fileTree(dir: "$rootDir/app/src/main/assets", exclude: ['*/*']).visit { fileDetails ->
+// if (fileDetails.directory) {
+// def odir = file("$rootDir/app/src/main/assets/$fileDetails.relativePath")
+// def ofile = file("$odir/uuid")
+// mkdir odir
+// ofile.text = UUID.randomUUID().toString()
+// }
+// }
+// }
+// }
+// preBuild.dependsOn genUUID
def kotlin_version = getExtOrDefault('kotlinVersion')
diff --git a/android/src/main/java/com/reactnativevosk/VoskModule.kt b/android/src/main/java/com/reactnativevosk/VoskModule.kt
index 0e2b6595b1b2cf1ee01c6c64239c4b0ea37fce19..5a8539b9cce8951967640dba755e29a4e3ff404a 100644
--- a/android/src/main/java/com/reactnativevosk/VoskModule.kt
+++ b/android/src/main/java/com/reactnativevosk/VoskModule.kt
@@ -19,13 +19,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
return "Vosk"
}
+ @ReactMethod
+ fun addListener(type: String?) {
+ // Keep: Required for RN built in Event Emitter Calls.
+ }
+
+ @ReactMethod
+ fun removeListeners(type: Int?) {
+ // Keep: Required for RN built in Event Emitter Calls.
+ }
+
override fun onResult(hypothesis: String) {
// Get text data from string object
val text = getHypothesisText(hypothesis)
// Stop recording if data found
if (text != null && text.isNotEmpty()) {
- cleanRecognizer();
+ // Don't auto-stop the recogniser - we want to do that when the user
+ // presses on "stop" only.
+ // cleanRecognizer();
sendEvent("onResult", text)
}
}
@@ -93,12 +105,11 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
@ReactMethod
fun loadModel(path: String, promise: Promise) {
cleanModel();
- StorageService.unpack(context, path, "models",
- { model: Model? ->
- this.model = model
- promise.resolve("Model successfully loaded")
- }
- ) { e: IOException ->
+
+ try {
+ this.model = Model(path);
+ promise.resolve("Model successfully loaded")
+ } catch (e: IOException) {
this.model = null
promise.reject(e)
}
@@ -153,6 +164,25 @@ class VoskModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMo
cleanRecognizer();
}
+ @ReactMethod
+ fun stopOnly() {
+ if (speechService != null) {
+ speechService!!.stop()
+ }
+ }
+
+ @ReactMethod
+ fun cleanup() {
+ if (speechService != null) {
+ speechService!!.shutdown();
+ speechService = null
+ }
+ if (recognizer != null) {
+ recognizer!!.close();
+ recognizer = null;
+ }
+ }
+
@ReactMethod
fun unload() {
cleanRecognizer();
diff --git a/lib/typescript/index.d.ts b/lib/typescript/index.d.ts
index 441e41cc402cca3a60b34978ef4fea976076259c..a173acebb4b314402550442ad471e0f7c706e3c4 100644
--- a/lib/typescript/index.d.ts
+++ b/lib/typescript/index.d.ts
@@ -10,6 +10,8 @@ export default class Vosk {
currentRegisteredEvents: EmitterSubscription[];
start: (grammar?: string[] | null) => Promise<String>;
stop: () => void;
+ stopOnly: () => void;
+ cleanup: () => void;
unload: () => void;
onResult: (onResult: (e: VoskEvent) => void) => EventSubscription;
onFinalResult: (onFinalResult: (e: VoskEvent) => void) => EventSubscription;
diff --git a/package.json b/package.json
index 707eddb8d68007f93071ac659c5b087c935c5f01..90ebe20f224eeec472c377df1fef9b15f2ff8200 100644
--- a/package.json
+++ b/package.json
@@ -11,12 +11,9 @@
"src",
"lib",
"android",
- "ios",
"cpp",
- "react-native-vosk.podspec",
"!lib/typescript/example",
"!android/build",
- "!ios/build",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__"
diff --git a/react-native-vosk.podspec b/react-native-vosk.podspec
deleted file mode 100644
index e3d41b90c5eef890c7a5108aaf16ac07d34a698b..0000000000000000000000000000000000000000
--- a/react-native-vosk.podspec
+++ /dev/null
@@ -1,41 +0,0 @@
-require "json"
-
-package = JSON.parse(File.read(File.join(__dir__, "package.json")))
-folly_version = '2021.06.28.00-v2'
-folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
-
-Pod::Spec.new do |s|
- s.name = "react-native-vosk"
- s.version = package["version"]
- s.summary = package["description"]
- s.homepage = package["homepage"]
- s.license = package["license"]
- s.authors = package["author"]
-
- s.platforms = { :ios => "10.0" }
- s.source = { :git => "https://github.com/riderodd/react-native-vosk.git", :tag => "#{s.version}" }
-
- s.source_files = "ios/**/*.{h,m,mm,swift}"
- s.resource_bundles = { 'Vosk' => ['ios/Vosk/*'] }
-
- s.dependency "React-Core"
- s.frameworks = "Accelerate"
- s.library = "c++"
- s.vendored_frameworks = "ios/libvosk.xcframework"
- s.requires_arc = true
-
- # Don't install the dependencies when we run `pod install` in the old architecture.
- if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
- s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
- s.pod_target_xcconfig = {
- "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
- "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
- }
-
- s.dependency "React-Codegen"
- s.dependency "RCT-Folly", folly_version
- s.dependency "RCTRequired"
- s.dependency "RCTTypeSafety"
- s.dependency "ReactCommon/turbomodule/core"
- end
-end
diff --git a/src/index.tsx b/src/index.tsx
index d9f90c921d89b1b4d85e145443ed3376546a368a..29e4068dbd7500828a73145bd25497a52c9bf638 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -69,6 +69,15 @@ export default class Vosk {
VoskModule.stop();
};
+ stopOnly = () => {
+ VoskModule.stopOnly();
+ };
+
+ cleanup = () => {
+ this.cleanListeners();
+ VoskModule.cleanup();
+ };
+
unload = () => {
this.cleanListeners();
VoskModule.unload();

File diff suppressed because one or more lines are too long

875
.yarn/releases/yarn-3.8.3.cjs vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,20 +2,17 @@ nmHoistingLimits: workspaces
nodeLinker: node-modules
compressionLevel: mixed
enableGlobalCache: false
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"
yarnPath: .yarn/releases/yarn-4.9.2.cjs
yarnPath: .yarn/releases/yarn-3.8.3.cjs
logFilters:
# Disable useless non-actionable warnings.
# https://github.com/yarnpkg/yarn/issues/4064
# e.g. "Some peer dependencies are incorrectly met by dependencies; run yarn explain peer-requirements for details."
- code: YN0086
level: discard
# eg "@joplin/app-desktop@workspace:packages/app-desktop provides react (p87edd) with version 18.2.0, which doesn't satisfy what @testing-library/react-hooks and some of its descendants request"
- code: YN0060
level: discard

View File

@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 682.66669 682.66669"
height="682.66669"
width="682.66669"
xml:space="preserve"
id="svg2"
version="1.1"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
sodipodi:docname="JoplinLetterBlue.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview13"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
showgrid="false"
inkscape:zoom="0.77490232"
inkscape:cx="366.49781"
inkscape:cy="360.69062"
inkscape:window-width="1366"
inkscape:window-height="708"
inkscape:window-x="0"
inkscape:window-y="30"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<defs
id="defs6">
<linearGradient
id="linearGradient26"
spreadMethod="pad"
gradientTransform="matrix(-4387.91,4387.91,4387.91,4387.91,4753.95,366.05)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0">
<stop
id="stop22"
offset="0"
style="stop-opacity:1;stop-color:#004caf" />
<stop
id="stop24"
offset="1"
style="stop-opacity:1;stop-color:#1f95f8" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath829"><path
id="path831"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.999997"
d="M 3961.59,4435.23 H 2570.18 c -13.15,0 -23.78,-10.64 -23.78,-23.77 v -441.84 c 0,-14.87 12.04,-26.92 26.92,-26.92 h 190.77 c 77.16,0 139.73,-59.35 146.43,-134.77 V 3505 3336.23 1728.75 1717.36 h -0.052 c 0.48,-16.84 -0.1898,-33.4 -1.83,-49.71 -0.18,-2.38 -0.5003,-4.73 -0.7902,-7.09 -1.0998,-9.53 -2.3199,-19.01 -4.17,-28.29 -1.0098,-5.29 -2.4399,-10.44 -3.7098,-15.65 -1.71,-6.93 -3.09,-13.97 -5.22,-20.75 -12.5802,-40.27 -32.4702,-77.62 -59.9802,-110.5 -1.0098,-1.17 -2.2599,-2.25 -3.2598,-3.41 -8.3901,-9.72 -17.2002,-19.19 -26.9502,-28.06 -9.84,-8.95 -20.2599,-17.27 -31.2099,-25 -77.8401,-55.14 -182.61,-79.4 -299.67,-68.2 -149.2599,14.03 -297.3399,81.72 -417.03,190.62 -119.6701,108.89 -194.08,243.62 -209.4799,379.41 -13.8501,121.48 22.5498,228.38 102.42,301.05 0.21,0.1598 0.3997,0.3098 0.5602,0.48 3.09,2.77 6.4901,5.2 9.6701,7.87 57.16,47.89 131.6701,76.91 216.7,84.91 0.96,0.09 1.8801,0.24 2.79,0.3203 8.9499,0.79 18.0699,1.15 27.27,1.49 4.8099,0.1598 9.5601,0.5003 14.4399,0.54 1.62,0.023 3.1602,0.1898 4.7802,0.1898 2.8998,0 5.91,-0.3803 8.8098,-0.42 13.4001,-0.21 26.9001,-0.7601 40.6701,-1.9401 1.74,-0.1402 3.3999,-0.08 5.19,-0.24 1.2699,-0.1297 2.5299,-0.4102 3.8001,-0.54 78,-7.82 155.2299,-31.11 228.5199,-66.3999 1.53,-0.068 3.3,-0.54 5.5099,-1.7601 22.34,-12.3399 26.6201,0.9 27.2801,9.6501 v 382.2399 282.8201 c 0,19.05 -13.2501,35.8999 -31.83,39.99 -394.7601,86.88 -782.08,-3.5501 -1055.38,-252.3401 -238.7499,-217.1799 -354.24,-530.5799 -316.8201,-859.7899 33.39,-293.23 183.9102,-574.94 423.88,-793.33 233.8901,-212.79003 531.69,-345.86006 838.8801,-374.80106 42.33,-3.918 84.8601,-5.93797 126.36,-5.93797 293.3799,0 565.6099,100.59802 766.54,283.37903 190.3401,173.3 304.35,411.27 321.0799,670.16 l 1.55,1697.91 h 0.1703 v 453.97 h 0.06 v 7.92 c 1.72,80.1199 67.05,144.58 147.61,144.58 h 190.77 c 14.8599,0 26.9199,12.05 26.9199,26.9199 v 441.84 c 0,13.13 -10.6299,23.77 -23.7799,23.77" /></clipPath></defs>
<g
id="g14"
transform="matrix(0.13333333,0,0,-0.13333333,0,682.66667)"
mask="none"
clip-path="url(#clipPath829)">
<g
clip-path="url(#clipPath20)"
id="g16">
<path
id="path28"
style="fill:url(#linearGradient26);fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 3873.89,0 H 1246.11 C 560.754,0 0,560.75 0,1246.11 V 3873.88 C 0,4559.25 560.754,5120 1246.11,5120 H 3873.89 C 4559.25,5120 5120,4559.25 5120,3873.88 V 1246.11 C 5120,560.75 4559.25,0 3873.89,0" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -48,7 +48,7 @@ const updateListWithDetails = function (dom, el, detail) {
};
const removeStyles = (dom, element: HTMLElement, styles: string[]) => {
Tools.each(styles, (style) => dom.setStyle(element, style, ''));
Tools.each(styles, (style) => dom.setStyle(element, { [style]: '' }));
};
const getEndPointNode = function (editor, rng, start, root) {

View File

@@ -8,6 +8,7 @@
import { Node } from '@ephox/dom-globals';
import { Arr, Option } from '@ephox/katamari';
import { HTMLElement } from '@ephox/sand';
import DomQuery from 'tinymce/core/api/dom/DomQuery';
import Editor from 'tinymce/core/api/Editor';
import Tools from 'tinymce/core/api/util/Tools';
import * as NodeType from './NodeType';
@@ -48,7 +49,7 @@ const findParentListItemsNodes = function (editor, elms) {
return parentLi ? parentLi : elm;
});
return [...new Set(listItemsElms)];
return DomQuery.unique(listItemsElms);
};
const getSelectedListItems = function (editor) {
@@ -88,7 +89,7 @@ const getSelectedListRoots = (editor: Editor): Node[] => {
const getUniqueListRoots = (editor: Editor, lists: Node[]): Node[] => {
const listRoots = Arr.map(lists, (list) => findLastParentListNode(editor, list).getOr(list));
return [...new Set(listRoots)];
return DomQuery.unique(listRoots);
};
const isList = (editor: Editor): boolean => {

View File

@@ -48,7 +48,8 @@ const listState = function (editor: Editor, listName, options:any = {}) {
const register = function (editor: Editor) {
const hasPlugin = function (editor, plugin) {
return editor.hasPlugin(plugin);
const plugins = editor.settings.plugins ? editor.settings.plugins : '';
return Tools.inArray(plugins.split(/[ ,]/), plugin) !== -1;
};
const _ = Settings.getLocalizationFunction(editor);

File diff suppressed because one or more lines are too long

View File

@@ -1300,9 +1300,4 @@ footer .bottom-links-row p {
:lang(zh-cn) #plans-section .faq {
display: none;
}
.cfa-button {
margin-top: 10px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -80,7 +80,7 @@ async function setupDownloadPage() {
if (href.indexOf('-Setup') > 0) downloadLinks['windows'] = href;
if (href.indexOf('.dmg') > 0) downloadLinks['macOs'] = href;
if (href.indexOf('arm64.DMG') > 0) downloadLinks['macOsM1'] = href;
if (href.endsWith('arm64.DMG')) downloadLinks['macOsM1'] = href;
if (href.indexOf('.AppImage') > 0) downloadLinks['linux'] = href;
});
@@ -98,8 +98,6 @@ async function setupDownloadPage() {
} else {
const os = await getOs();
console.info('Found OS: ' + os);
if (os === 'macOsUndefined') {
// If we don't know which macOS version it is, we let the user choose.
$('.main-content .intro').html('<p class="macos-m1-info">The macOS release is available for Intel processors or for Apple Silicon (M1) processors. Please select your version:</p>');

View File

@@ -1,215 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: Milo Ivir <mail@mivirtype.de>\n"
"Language-Team: \n"
"Language: hr_HR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.6\n"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:13
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:9
msgid "/month"
msgstr "/mjesec"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/partials/plan.mustache:19
msgid "/year"
msgstr "/godina"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:8
msgid ""
"<a href=\"https://joplincloud.com\">Joplin Cloud</a> allows you to "
"synchronise your notes across devices. It also lets you publish notes, and "
"collaborate on notebooks with your friends, family or colleagues."
msgstr ""
"<a href=\"https://joplincloud.com\">Joplin Cloud</a> omogućuje "
"sinkronizaciju bilješki na različitim uređajima. Omogućuje i objavljivanje "
"bilješki i suradnju na bilježnicama s prijateljima, obitelji ili kolegama."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:205
msgid "<span class=\"frame-bg frame-bg-yellow-lg\">Customise</span> it"
msgstr "<span class=\"frame-bg frame-bg-yellow-lg\">Prilagodi</span> uslugu"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:104
msgid "<span class=\"frame-bg frame-bg-yellow\">Multimedia</span> notes"
msgstr "<span class=\"frame-bg frame-bg-yellow\">Multimedijske</span> bilješke"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:256
msgid "100% <span class=\"frame-bg frame-bg-yellow-lg\">your data</span>"
msgstr "100 % <span class=\"frame-bg frame-bg-yellow-lg\">tvoji podaci</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:298
msgid "A <span class=\"frame-bg frame-bg-yellow-lg\">French</span> Alternative"
msgstr ""
"<span class=\"frame-bg frame-bg-yellow-lg\">Francuska</span> alternativa"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:236
msgid ""
"Access your notes from your computer, phone or tablet by synchronising with "
"various services, including Joplin Cloud, Dropbox and OneDrive. The app is "
"available on Windows, macOS, Linux, Android and iOS. A terminal app is also "
"available!"
msgstr ""
"Pristupi svojim bilješkama s računala, mobitela ili tableta sinkronizacijom "
"s raznim uslugama, uključujući Joplin Cloud, Dropbox i OneDrive. Program je "
"dostupan za Windows, macOS, Linux, Android i iOS sustave. Dostupan je i "
"program za terminal!"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:49
msgid ""
"Already have a Joplin Cloud account? <a href=\"https://"
"joplincloud.com\">Login now</a>"
msgstr ""
"Već imaš Joplin Cloud račun? <a href=\"https://joplincloud.com\">Prijavi se "
"sada</a>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:208
msgid ""
"Customise the app with plugins, custom themes and multiple text editors "
"(Rich Text or Markdown). Or create your own scripts and plugins using the "
"Extension API."
msgstr ""
"Prilagodi program pomoću dodataka, prilagođenih tema i uređivača teksta "
"(formatirani tekst ili Markdown). Ili izradi vlastita skripta i dodatke "
"pomoću API-ja za proširenja."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:242
msgid "Download it now"
msgstr "Preuzmi sada"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:112
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:63
msgid "Download the app"
msgstr "Preuzmi program"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:213
msgid "Find out more"
msgstr "Saznaj više"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:54
msgid "Free your <span class=\"frame-bg frame-bg-blue\">notes</span>"
msgstr "Oslobodi svoje <span class=\"frame-bg frame-bg-blue\">bilješke</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:175
msgid "Get the clipper"
msgstr "Nabavi Clipper"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:107
msgid ""
"Images, videos, PDFs and audio files are supported. Create math expressions "
"and diagrams directly from the app. Take photos with the mobile app and save "
"them to a note."
msgstr ""
"Podržane su slike, videozapisi, PDF-ovi i audio datoteke. Stvori matematičke "
"izraze i dijagrame izravno iz programa. Snimaj fotografije s programom za "
"mobitel i spremi ih u bilješku."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:327
msgid "In the <span class=\"frame-bg frame-bg-yellow\">Press</span>"
msgstr "<span class=\"frame-bg frame-bg-yellow\">Recenzije</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:5
msgid "Joplin Cloud <span class=\"frame-bg frame-bg-yellow\">plans</span>"
msgstr "Joplin Cloud <span class=\"frame-bg frame-bg-yellow\">tarife</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:301
msgid ""
"Joplin Cloud is based in France. This means your data is protected by strict "
"European Union privacy laws. In addition, Joplin Cloud implements strong end-"
"to-end encryption so that not even us can have access to your data."
msgstr ""
"Joplin Cloud ima sjedište u Francuskoj. To znači da su tvoji podaci "
"zaštićeni strogim zakonima o privatnosti Europske unije. Osim toga, Joplin "
"Cloud implementira snažno sveobuhvatno šifriranje (end-to-end encryption) "
"tako da čak ni mi ne možemo pristupiti tvojim podacima."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:57
msgid ""
"Joplin is an open source note-taking app. Capture your thoughts and securely "
"access them from any device."
msgstr ""
"Joplin je program za bilješke otvorenog koda. Zabilježi svoje misli i "
"sigurno im pristupi s bilo kojeg uređaja."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:262
msgid "More about E2EE"
msgstr "Više o E2EE"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:391
msgid "Our <span class=\"frame-bg frame-bg-blue-lg\">sponsors</span>"
msgstr "Naši <span class=\"frame-bg frame-bg-blue-lg\">sponzori</span>"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:23
msgid "Pay Monthly"
msgstr "Plaćaj mjesečno"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/plans.mustache:30
msgid "Pay Yearly"
msgstr "Plaćaj godišnje"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:167
msgid ""
"Save <span class=\"frame-bg frame-bg-blue\">web pages</span> <br>as notes"
msgstr ""
"Spremaj <span class=\"frame-bg frame-bg-blue\">web stranice</span> <br>kao "
"bilješke"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:65
msgid "Sign up with Joplin Cloud"
msgstr "Registriraj se na Joplin Cloud"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:394
msgid "Thank you for your support!"
msgstr "Hvala ti na podršci!"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:257
msgid ""
"The app is open source and your notes are saved to an open format, so you'll "
"always have access to them. Uses End-To-End Encryption (E2EE) to secure your "
"notes and ensure no-one but yourself can access them."
msgstr ""
"Program je otvorenog koda i tvoje se bilješke spremaju u otvorenom formatu, "
"tako da ćeš im uvijek moći pristupiti. Program koristi sveobuhvatno "
"šifriranje – engl. End-To-End Encryption (E2EE) – kako bi zaštitila tvoje "
"bilješke i osigurala da im nitko osim tebe ne može pristupiti."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:144
msgid "Try it now"
msgstr "Isprobaj sada"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:170
msgid ""
"Use the web clipper extension, available on Chrome and Firefox, to save web "
"pages or take screenshots as notes."
msgstr ""
"Koristi proširenje Web Clipper, dostupno za Chrome i Firefox, za spremanje "
"web stranica ili snimanje ekrana kao bilješku."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:138
msgid ""
"With Joplin Cloud, share your notes with your friends, family or colleagues "
"and collaborate on them."
msgstr ""
"Joplin Cloud ti omogućuje da dijeliš bilješke s prijateljima, obitelji ili "
"kolegama te da na njima surađujete."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:137
msgid "Work <span class=\"frame-bg frame-bg-yellow\">together</span>"
msgstr "<span class=\"frame-bg frame-bg-yellow\">Surađuj</span> s drugima"
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:141
msgid ""
"You can also publish a note to the internet and share the URL with others."
msgstr "Bilješke možeš objaviti i na internetu te dijeliti URL s drugima."
#: /Users/laurent/src/joplin/Assets/WebsiteAssets/templates/front.mustache:233
msgid ""
"Your notes, <span class=\"frame-bg frame-bg-blue-lg\">everywhere</span> you "
"are"
msgstr ""
"Tvoje bilješke, <span class=\"frame-bg frame-bg-blue-lg\">gdje god</span> se "
"nalaziš"

View File

@@ -1,170 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Mon, 22 Sep 2025 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Mon, 22 Sep 2025 00:00:00 GMT</pubDate><item><title><![CDATA[What's new in Joplin 3.4]]></title><description><![CDATA[<p>Joplin 3.4 includes many bug fixes and improvements, with a focus on the mobile app.</p>
<h2>Mobile<a name="mobile" href="#mobile" class="heading-anchor">🔗</a></h2>
<h3>Rich Text Editor<a name="rich-text-editor" href="#rich-text-editor" class="heading-anchor">🔗</a></h3>
<p>The mobile app now includes a beta <a href="https://joplinapp.org/help/apps/rich_text_editor">Rich Text Editor</a>! The new editor renders formatting/math/images within the editor:</p>
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-mobile-rte.png" width="400" alt="screenshot: Mobile Rich Text Editor editing the welcome notes. Images, headings, etc are rendering."/>
<p>To try it, 1) open a note in the default Markdown editor 2) open the note actions menu (the three vertical dots) for the note and 3) click “Edit as Rich Text”.</p>
<p>Be aware that this editor is still in active development and <a href="https://github.com/laurent22/joplin/issues/12840">has a number of known limitations and issues</a>. The Rich Text editor is based on <a href="https://prosemirror.net/">ProseMirror</a> and will behave differently from the desktop Rich Text Editor in many cases.</p>
<h3>Support for publishing notes with Joplin Cloud and Server<a name="support-for-publishing-notes-with-joplin-cloud-and-server" href="#support-for-publishing-notes-with-joplin-cloud-and-server" class="heading-anchor">🔗</a></h3>
<p>It's now possible to <a href="https://joplinapp.org/help/apps/publish_note">publish notes</a> from the mobile app! To do so, open the “Properties” menu for a note, then click “Publish/unpublish”:</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-publish-notes.png" alt="screenshot: A Publish/unpublish note action is shown in the &quot;Note properties&quot; sidebar, just below a &quot;Previous versions&quot; button"></p>
<p>Next, in the “publish note” dialog, click “Copy shareable link”. Notes can later be unpublished by clicking &quot;Unpublish&quot; in the publication dialog.</p>
<h3>Viewing note history<a name="viewing-note-history" href="#viewing-note-history" class="heading-anchor">🔗</a></h3>
<p>It is now possible to view and restore previous note versions from the mobile app. Like the &quot;publish note&quot; feature, previous note versions can be accessed from the note properties menu.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-note-history.png" alt="screenshot: The note history page"></p>
<p>As on desktop, the note history feature can be configured from the “Note History” tab in settings.</p>
<h3>Updated tag dialog<a name="updated-tag-dialog" href="#updated-tag-dialog" class="heading-anchor">🔗</a></h3>
<p>The tag dialog has been redesigned, with a new UI for adding, removing, and creating new tags:<br>
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-tag-editor.png" width="500" alt="screenshot: Tag dialog now consists of three sections: Added tags, Add new tags, Actions."/></p>
<h3>Android: Improved voice typing<a name="android-improved-voice-typing" href="#android-improved-voice-typing" class="heading-anchor">🔗</a></h3>
<p>The voice typing feature on Android has been updated with <a href="https://github.com/laurent22/joplin/pull/12404">improved silence detection</a> and a new “<a href="https://github.com/laurent22/joplin/pull/12370">custom glossary</a>” setting. Voice typing also now <a href="https://github.com/laurent22/joplin/pull/12352">defaults to a more accurate (but somewhat slower) model</a>.</p>
<h3>Quickly creating a note from multiple photos<a name="quickly-creating-a-note-from-multiple-photos" href="#quickly-creating-a-note-from-multiple-photos" class="heading-anchor">🔗</a></h3>
<p>A “scan notebook” action has been added to the “New note” menu:</p>
<img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250922-scan-notebook.png" width="500"/>
<p>This action allows quickly creating a new note with multiple pictures taken from the camera.</p>
<h2>Desktop<a name="desktop" href="#desktop" class="heading-anchor">🔗</a></h2>
<h3>More Markdown Editor settings<a name="more-markdown-editor-settings" href="#more-markdown-editor-settings" class="heading-anchor">🔗</a></h3>
<p>The &quot;Note&quot; tab in settings now includes new settings for the Markdown editor, including:</p>
<ul>
<li>An option to render headers, lists, and certain other formatting within the editor.</li>
<li>An option to render images in the editor.</li>
</ul>
<p>When enabled, these settings bring the Markdown editor closer to the Rich Text Editor, without <a href="https://joplinapp.org/help/apps/rich_text_editor">some of the Rich Text Editor's limitations</a>.</p>
<p>These settings are also available on mobile.</p>
<h3>Smaller application size and faster startup<a name="smaller-application-size-and-faster-startup" href="#smaller-application-size-and-faster-startup" class="heading-anchor">🔗</a></h3>
<p>We've made the desktop application roughly 33% smaller! In addition to faster application startup, this means that the desktop app should be faster to download take up less space.</p>
<table class="table">
<thead>
<tr>
<th>Joplin version</th>
<th>Previous size (v3.3.13)</th>
<th>New size (v3.4.12)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Joplin for MacOS (ARM)</td>
<td>211 MB</td>
<td>141 MB</td>
</tr>
<tr>
<td>Joplin for Windows (installer)</td>
<td>321 MB</td>
<td>219 MB</td>
</tr>
<tr>
<td>Joplin for Windows (portable)</td>
<td>320 MB</td>
<td>219 MB</td>
</tr>
<tr>
<td>Joplin for Linux (AppImage)</td>
<td>219 MB</td>
<td>147 MB</td>
</tr>
</tbody>
</table>
<h2>Terminal app<a name="terminal-app" href="#terminal-app" class="heading-anchor">🔗</a></h2>
<h3>Collapsible folders<a name="collapsible-folders" href="#collapsible-folders" class="heading-anchor">🔗</a></h3>
<p>The <a href="https://joplinapp.org/help/apps/terminal/">terminal application</a> now supports expanding and collapsing folders by pressing <kbd>z</kbd>. For additional information, see <a href="https://github.com/laurent22/joplin/pull/12718">the original pull request</a>.</p>
<h3>Managing shared notebooks and published notes<a name="managing-shared-notebooks-and-published-notes" href="#managing-shared-notebooks-and-published-notes" class="heading-anchor">🔗</a></h3>
<p>New commands have been added to the terminal app, including <code>publish</code>, <code>unpublish</code>, and <code>share</code>. This allows the terminal app to manage shared folders and published notes.</p>
<h2>Bug fixes<a name="bug-fixes" href="#bug-fixes" class="heading-anchor">🔗</a></h2>
<p>For the full list of changes, see <a href="https://joplinapp.org/help/about/changelog/desktop/">the desktop changelog</a> and <a href="https://joplinapp.org/help/about/changelog/android/">the mobile changelog</a>.</p>
]]></description><link>https://joplinapp.org/news/20250922-release-3-4</link><guid isPermaLink="false">20250922-release-3-4</guid><pubDate>Mon, 22 Sep 2025 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[What's new in Joplin 3.3]]></title><description><![CDATA[<h2>Desktop application<a name="desktop-application" href="#desktop-application" class="heading-anchor">🔗</a></h2>
<h3>Accessibility improvements<a name="accessibility-improvements" href="#accessibility-improvements" class="heading-anchor">🔗</a></h3>
<p>The Joplin 3.3 release introduces significant accessibility enhancements designed to make the application more inclusive and user-friendly. Users can now benefit from improved keyboard navigation, thanks to newly added shortcuts and clearer labels that streamline interaction across the interface. We've also added a &quot;go to viewer&quot; menu item that moves focus from the note editor to the note viewer. Focus is moved to the location in the viewer corresponding to the location of the cursor in the editor.</p>
<p>Screen reader support has been bolstered, ensuring elements like the note list and sidebar are easier to toggle and interact with. These updates make the application more usable for individuals relying on assistive technologies.</p>
<p>Additionally, visual improvements, including increased contrast for UI components such as URLs, sidebars, and scrollbars, enhance readability for users with visual impairments. This focus on clarity ensures a more comfortable user experience.</p>
<p>The Rich Text Editor has also received accessibility-focused updates, allowing for more seamless interaction with code blocks using either a keyboard or touchscreen. These refinements highlight Joplin's dedication to creating an accessible and equitable experience for all users.</p>
<h3>Button to collapse and expand all notebooks<a name="button-to-collapse-and-expand-all-notebooks" href="#button-to-collapse-and-expand-all-notebooks" class="heading-anchor">🔗</a></h3>
<p>Joplin 3.3 introduces a convenient &quot;Collapse/Expand All&quot; button for notebooks, allowing you to quickly adjust the visibility of your notebook hierarchy. This feature simplifies navigation by letting you expand all notebooks to locate specific notes or collapse them for a tidier interface!</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250428-collapse-all.png" alt=""></p>
<h3>New dialog to select a note and link to it<a name="new-dialog-to-select-a-note-and-link-to-it" href="#new-dialog-to-select-a-note-and-link-to-it" class="heading-anchor">🔗</a></h3>
<p>A new dialog has been added to make linking to notes easier. By pressing Shift+Option+L on macOS or Shift+Alt+L on Windows and Linux, you can quickly bring up a search box. Simply type the name of the note you want to link to, and the link will be added to your current note!</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250428-link-notes.png" alt=""></p>
<h3>Support for multiple instances of Joplin<a name="support-for-multiple-instances-of-joplin" href="#support-for-multiple-instances-of-joplin" class="heading-anchor">🔗</a></h3>
<p>Joplin Desktop now <a href="https://joplinapp.org/help/apps/multiple_instances">lets you run multiple instances at once</a>! This means you can easily separate your work and personal notes, or use Joplin across different virtual desktops. Each instance runs independently with its own settings, plugins, and notes, so nothing overlaps. You can open a second instance through in menu <strong>File =&gt; Open secondary app instance...</strong>, and customise it however you like!</p>
<h3>Improved Rich Text editor<a name="improved-rich-text-editor" href="#improved-rich-text-editor" class="heading-anchor">🔗</a></h3>
<p>This version includes multiple improvements and bug fixes to the Rich Text Editor. In particular it has now been upgraded to TinyMCE v6, and it adds support for Markdown auto-replacement. For example, typing <code>==highlight==</code> creates highlighted text. Auto-replacement can be disabled in settings.</p>
<h2>Mobile application<a name="mobile-application" href="#mobile-application" class="heading-anchor">🔗</a></h2>
<h3>Accessibility improvements<a name="accessibility-improvements-1" href="#accessibility-improvements-1" class="heading-anchor">🔗</a></h3>
<p>Like the desktop app, the mobile app includes several accessibility improvements designed to enhance the user experience for those relying on assistive technologies. Focus handling has been improved in the note actions menu and modal dialogs, ensuring smoother navigation for screen reader users. Additionally, the default modal close button is now accessible, and issues with invisible buttons being focusable have been resolved.</p>
<p>Other updates include better contrast for faded URLs in the Markdown editor, making them more readable for users with visual impairments. The encryption configuration screen has been improved for better accessibility, and screen reader support has been added for creating and editing profiles. These changes collectively improve navigation, readability, and usability for all users.</p>
<h3>Support attaching audio recordings<a name="support-attaching-audio-recordings" href="#support-attaching-audio-recordings" class="heading-anchor">🔗</a></h3>
<p>You can now easily capture and include audio recordings directly within your notes. To use this feature, open the kebab menu and select &quot;Record audio.&quot; You can then to record your audio input. When finished, the app automatically attaches the recorded audio file to the note. This functionality is perfect for capturing ideas, reminders, or supplementary audio information in a quick and intuitive way.</p>
<h3>Improved voice typing feature<a name="improved-voice-typing-feature" href="#improved-voice-typing-feature" class="heading-anchor">🔗</a></h3>
<p>The voice typing feature in Android has undergone a significant improvement, making it more accurate. Previously introduced in version 2.11, the feature allowed you to transcribe speech into text but lacked punctuation and struggled with accuracy in certain scenarios. The revamped version now leverages Whisper, an advanced AI model, to deliver improved recognition, including automatic punctuation and paragraph formatting.</p>
<p>Despite its advancements, the feature is currently in beta due to the demanding nature of the required AI models. While it defaults to a smaller, less accurate model to accommodate older devices, you can <a href="https://github.com/joplin/voice-typing-models/releases">manually download and switch to more accurate models</a> for better performance.</p>
<p>As previously, the feature remains entirely offline, ensuring that private recordings are never sent to third-party servers, a distinct privacy advantage over similar solutions from Google or Apple. Additionally it means you can use the feature even when you don't have an internet connection. We plan to refine this feature further, eventually defaulting to the more accurate model as stability improves.</p>
<h3>Improved new note menu<a name="improved-new-note-menu" href="#improved-new-note-menu" class="heading-anchor">🔗</a></h3>
<p>The redesigned &quot;New Note&quot; menu takes note creation to a whole new level of flexibility and convenience. Previously, this menu only offered options to create a new note or a new to-do. With the latest update, you now have quick access to a variety of shortcuts, enabling you to attach files, record audio, capture photo notes, or even create drawings directly from the menu. This intuitive redesign makes it easier to choose the format that best suits your needs.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250428-new-note-menu.png" alt=""></p>
<h2>Security and bug fixes<a name="security-and-bug-fixes" href="#security-and-bug-fixes" class="heading-anchor">🔗</a></h2>
<p>As always, we continue to reinforce the security of Joplin. This version implements a robust content security policy for the Rich Text Editor, safeguarding the application against malicious content.</p>
<p>In total, this version delivers 39 bug fixes on desktop and 17 on mobile, enhancing both the security and stability of the application.</p>
<h2>Full changelogs<a name="full-changelogs" href="#full-changelogs" class="heading-anchor">🔗</a></h2>
<p>This is just an overview of the main features. The full changelogs are available there:</p>
<ul>
<li>Desktop: <a href="https://joplinapp.org/help/about/changelog/desktop">https://joplinapp.org/help/about/changelog/desktop</a></li>
<li>Android: <a href="https://joplinapp.org/help/about/changelog/android/">https://joplinapp.org/help/about/changelog/android/</a></li>
<li>iOS: <a href="https://joplinapp.org/help/about/changelog/ios/">https://joplinapp.org/help/about/changelog/ios/</a></li>
</ul>
]]></description><link>https://joplinapp.org/news/20250428-release-3-3</link><guid isPermaLink="false">20250428-release-3-3</guid><pubDate>Mon, 28 Apr 2025 00:00:00 GMT</pubDate><twitter-text>What&apos;s new in Joplin 3.3</twitter-text></item><item><title><![CDATA[What's new in Joplin 3.2]]></title><description><![CDATA[<h2>Import OneNote Archives<a name="import-onenote-archives" href="#import-onenote-archives" class="heading-anchor">🔗</a></h2>
<p>Joplin now supports importing OneNote archives, a significant step for users transitioning from OneNote. Microsoft has long made it challenging to leave OneNote, offering limited export options and complex formats that make it difficult for app developers to support it. Despite these hurdles, @pedr tackled these issues head-on, developing an import tool that simplifies the process. This addition makes Joplin a practical choice for those looking to move away from OneNote's ecosystem.</p>
<p>To use this feature, select <strong>File</strong> =&gt; <strong>Import</strong> =&gt; <strong>ZIP - OneNote Notebook</strong></p>
<h2>Multi-window support<a name="multi-window-support" href="#multi-window-support" class="heading-anchor">🔗</a></h2>
<p>We're excited to introduce Multi-Window Support, a highly requested feature that makes managing multiple notes easier than ever. With this update, you can open notes in different windows and each window operates independently, allowing you to compare notes, reference content, and organise projects with greater flexibility.</p>
<p>To use this feature, right-click on a note, select <strong>Open in...</strong> and select <strong>Edit in new window</strong></p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250114-multi-window.png" alt=""></p>
<h2>Customisable toolbar on mobile<a name="customisable-toolbar-on-mobile" href="#customisable-toolbar-on-mobile" class="heading-anchor">🔗</a></h2>
<p>The new customisable toolbar on mobile is now draggable, making it easier to access the buttons you need. You can also choose which buttons to display by tapping the Cog button, allowing for a more personalised and efficient note-editing experience!</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20250114-mobile-toolbar.png" alt=""></p>
<h2>Enhanced Accessibility<a name="enhanced-accessibility" href="#enhanced-accessibility" class="heading-anchor">🔗</a></h2>
<p>In order to implement the <a href="https://www.w3.org/TR/WCAG20/">WCAG 2.0 guidelines</a>, accessibility has seen a substantial upgrade thanks to the efforts of @personalizedrefrigerator. The desktop and mobile apps now offer better keyboard navigation, including improved functionality in dropdown menus and settings. Focus indicators have been made more visible, while ARIA labels have been added to boost compatibility with screen readers. Specific areas like note attachments, sidebars, and dialogs have also been optimised to ensure accessibility for all users.</p>
<h2>Refined Drawing and Markdown Editing<a name="refined-drawing-and-markdown-editing" href="#refined-drawing-and-markdown-editing" class="heading-anchor">🔗</a></h2>
<p>Joplin's drawing and editing features have been fine-tuned for a smoother experience. Freehand Drawing on mobile and desktop has been updated to version 2.14.0, addressing several usability issues and bugs. Additionally, the Freehand Drawing plugin is now part of the desktop app by default. These changes enhance the reliability and integration of the drawing tool.</p>
<h2>Faster and more secure encryption<a name="faster-and-more-secure-encryption" href="#faster-and-more-secure-encryption" class="heading-anchor">🔗</a></h2>
<p>For GSoC 2024, @wh201906 worked on optimising the encryption and decryption processes, boosting speed for mobile devices in particular (but desktop too). Additionally, the encryption security was improved by transitioning to a more robust 256-bit key.</p>
<p>As of now this feature is optional and can be enabled by going to the <strong>Configuration Screen</strong>, then <strong>Synchronisation</strong> =&gt; <strong>Advanced options</strong> =&gt; <strong>Use beta encryption</strong>.</p>
<h2>Expanded Plugin Support<a name="expanded-plugin-support" href="#expanded-plugin-support" class="heading-anchor">🔗</a></h2>
<p>Developers will appreciate the updates to Joplin's plugin ecosystem. A new API has been introduced to create <a href="https://joplinapp.org/api/references/plugin_api/classes/joplinviewsdialogs.html#showtoast">toast notifications</a>, alongside updates to CodeMirror packages. A new <a href="https://github.com/laurent22/joplin/blob/5ee8a9a45493683c72a36b52e1460b5acdd4f1ac/packages/lib/commands/renderMarkup.ts#L23"><code>renderMarkup</code></a> command has been introduced to allow you to render Markdown content to HTML using the Joplin built-in API.</p>
<h1>Full changelogs<a name="full-changelogs" href="#full-changelogs" class="heading-anchor">🔗</a></h1>
<p>This is just an overview of the main features. The full changelogs are available there:</p>
<ul>
<li>Desktop: <a href="https://joplinapp.org/help/about/changelog/desktop">https://joplinapp.org/help/about/changelog/desktop</a></li>
<li>Android: <a href="https://joplinapp.org/help/about/changelog/android/">https://joplinapp.org/help/about/changelog/android/</a></li>
<li>iOS: <a href="https://joplinapp.org/help/about/changelog/ios/">https://joplinapp.org/help/about/changelog/ios/</a></li>
</ul>
]]></description><link>https://joplinapp.org/news/20250114-release-3-2</link><guid isPermaLink="false">20250114-release-3-2</guid><pubDate>Tue, 14 Jan 2025 00:00:00 GMT</pubDate><twitter-text>What&apos;s new in Joplin 3.2</twitter-text></item><item><title><![CDATA[Project 4: Handwritten Text Recognition (HTR) for Joplin]]></title><description><![CDATA[<p>Joplin is partnering with a French government institution to bring you innovative new features! We will work on accessibility, voice typing, HTR and add Rocketbook integration. Today we'll present the planned HTR integration:</p>
<p>Currently, Joplin’s OCR (Optical Character Recognition) feature is designed to recognise printed text, which works great for scanning documents with standard fonts. However, we’re looking to expand this functionality to support handwritten text recognition (HTR), which would be beneficial to handle scanned, handwritten documents, as well as for the upcoming Rocketbook integration.</p>
<p>Handwritten text recognition is complex task, requiring significant processing power and large machine learning models. Because of this, we plan to implement HTR via a server, possibly integrated with Joplin Cloud or Joplin Server. The beauty of this approach is that handwritten text recognition is a rapidly evolving field, so we can continuously improve the server-side model. This means that every Joplin app can benefit from these updates without needing to redeploy or update the app itself.</p>
<p>For the Rocketbook integration, this integration will make a significant difference. Right now, your handwritten documents would be scanned as images, but with HTR, Joplin will be able to recognise the actual text you’ve written. Not only will your handwritten notes become searchable, but you’ll also be able to copy and paste the text into other documents.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20241217-htr.jpg" alt="HTR illustration"></p>
]]></description><link>https://joplinapp.org/news/20241217-project-4-htr</link><guid isPermaLink="false">20241217-project-4-htr</guid><pubDate>Tue, 17 Dec 2024 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Project 3: Rocketbook integration with Joplin]]></title><description><![CDATA[<p>Joplin is partnering with a French government institution to bring you innovative new features! We will work on accessibility, voice typing, HTR and add Rocketbook integration. Today we'll present the planned Rocketbook integration:</p>
<p><a href="https://getrocketbook.com/pages/how-rocketbook-works">Rocketbook</a> is a popular brand of smart notebooks designed to make note-taking more efficient and sustainable. These notebooks feature special erasable pages that you can write on with specific pens and then wipe clean with a damp cloth. What makes Rocketbook even more appealing is its ability to scan and upload your notes to cloud services for easy storage and sharing.</p>
<p>We plan to create an integration between Rocketbook and Joplin, designed to make the note-taking process even smoother. While Rocketbook typically works through its own official app, we plan to integrate it directly into Joplin without relying on third-party apps or APIs. This means that you can enjoy the benefits of Rocketbook’s smart features while using Joplin as your primary note-taking platform.</p>
<p>The great thing about this integration is that it’s not limited to just Rocketbook. As long as the smart notebook uses QR codes to identify pages, the same functionality will work. This means you can use Joplin with a wide variety of smart notebooks, making it a versatile tool for all your note-taking needs.</p>
<p>With this integration, we’re making it easier than ever to combine the power of smart notebooks with the flexibility of Joplin’s open-source platform. Whether you're using Rocketbook or another smart notebook, Joplin will be ready to help you organise and access your notes in the cloud!</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20241216-rocketbook.jpg" alt="Rocketbook notebook"></p>
]]></description><link>https://joplinapp.org/news/20241216-project-3-rocketbook</link><guid isPermaLink="false">20241216-project-3-rocketbook</guid><pubDate>Mon, 16 Dec 2024 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Project 2: Making Joplin more accessible with WCAG-2 compliance]]></title><description><![CDATA[<p>We're always looking for ways to make Joplin better for everyone, and one of the key steps in improving accessibility is implementing the <a href="https://www.w3.org/TR/WCAG20/">Web Content Accessibility Guidelines</a> (WCAG 2). These guidelines help ensure that our app is usable for all users, including those with disabilities, while also enhancing the overall user experience for everyone.</p>
<p>To get started with WCAG 2 support, we’ll run an accessibility audit with a tool such as <a href="https://wave.webaim.org">Web Accessibility Evaluation Tools</a> (WAVE). This will help us spot any accessibility issues in the app that we need to address.</p>
<p>Once the audit is complete, we'll take action on the issues we find. Here's a look at some of the things we'll focus on:</p>
<ul>
<li>
<p><strong>Making content easier to perceive</strong>: We’ll make sure there are text alternatives for non-text content, provide captions for multimedia, and check that colour contrast is strong enough for easy reading.</p>
</li>
<li>
<p><strong>Improving operability</strong>: Every feature will be accessible through the keyboard, ensuring that users who can't rely on a mouse can still navigate easily.</p>
</li>
<li>
<p><strong>Enhancing comprehension</strong>: We’ll ensure that the text is readable, the layout is predictable, and input assistance is available for those who need it.</p>
</li>
</ul>
<p>We’ll also use ARIA standards and test for compatibility with assistive technologies to make sure everything works well with tools like screen readers.</p>
<p>To ensure we're on the right track, we’ll invite users with disabilities to test the app and help us identify any remaining barriers. Accessibility is something we’ll keep working on, so we'll continue testing, refining, and making improvements to ensure Joplin stays accessible to everyone. It’s a journey, and we’re committed to making the experience better for all our users.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20241207-wcag2.jpg" alt="WCAG 2 logo"></p>
]]></description><link>https://joplinapp.org/news/20241207-project-2-wcag2</link><guid isPermaLink="false">20241207-project-2-wcag2</guid><pubDate>Sat, 07 Dec 2024 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Project 1: Making voice typing even better for everyone]]></title><description><![CDATA[<p>Joplin is partnering with a French government institution to bring you innovative new features! We will work on accessibility, voice typing, HTR and add Rocketbook integration. Today we'll present the planned improvements to voice typing:</p>
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Joplin]]></title><description><![CDATA[Joplin, the open source note-taking application]]></description><link>https://joplinapp.org</link><generator>RSS for Node</generator><lastBuildDate>Thu, 28 Nov 2024 00:00:00 GMT</lastBuildDate><atom:link href="https://joplinapp.org/rss.xml" rel="self" type="application/rss+xml"/><pubDate>Thu, 28 Nov 2024 00:00:00 GMT</pubDate><item><title><![CDATA[Project 1: Making voice typing even better for everyone]]></title><description><![CDATA[<p>Joplin is partnering with a French government institution to bring you innovative new features! We will work on accessibility, voice typing, HTR and add Rocketbook integration. Today we'll present the planned improvements to voice typing:</p>
<p>Right now, voice input works pretty well, but there’s one thing that still needs improvement: punctuation. Our current system is accurate, but it doesn’t pick up on things like commas or periods, which can make spoken text harder to understand. That’s why we’re looking into other voice recognition engines that can handle punctuation better while keeping the accuracy we need.</p>
<p>Improving voice input like this isn’t just about convenience – it’s about making our app more accessible to everyone. For people with visual impairments, being able to use voice input means they don’t have to rely on typing. Those with motor difficulties can control the app without needing to use their hands. And for users with dyslexia or other learning challenges, voice input can be much easier and more natural than typing out words.</p>
<p>We’re excited to experiment with this new feature, knowing it could make a real difference for people who rely on voice technology to get things done.</p>
@@ -519,4 +353,49 @@ sys 0m38.013s</p>
<p>Unfortunately we cannot publish the Android version because it is based on a framework version that Google does not accept. To upgrade the app a lot of changes are needed and another round of pre-releases, and therefore there will not be a 2.9 version for Google Play. You may however download the official APK directly from there: <a href="https://github.com/laurent22/joplin-android/releases/tag/android-v2.9.8">Android 2.9 Official Release</a></p>
<p>This is the reality of app stores in general - small developers being imposed never ending new requirements by all-powerful companies, and by the time a version is finally ready we can't even publish it because yet more requirements are in place.</p>
<p>For the record the current 2.9 app works perfectly fine. It targets Android 11, which is only 2 years old and is still supported (and installed on millions of phones). Google requires us to target Android 12 which only came out last year.</p>
]]></description><link>https://joplinapp.org/news/20221216-release-2-9</link><guid isPermaLink="false">20221216-release-2-9</guid><pubDate>Fri, 16 Dec 2022 00:00:00 GMT</pubDate><twitter-text>What&apos;s new in Joplin 2.9</twitter-text></item></channel></rss>
]]></description><link>https://joplinapp.org/news/20221216-release-2-9</link><guid isPermaLink="false">20221216-release-2-9</guid><pubDate>Fri, 16 Dec 2022 00:00:00 GMT</pubDate><twitter-text>What&apos;s new in Joplin 2.9</twitter-text></item><item><title><![CDATA[Joplin is hiring!]]></title><description><![CDATA[<p>Joplin is an open source note-taking app. Capture your thoughts and securely access them from any device.</p>
<p>We are looking to hire two JavaScript software developers to work on the desktop, mobile, and server applications. All those are built using modern technologies, including React, React Native and Electron with a strong focus on test units.</p>
<p>You need to demonstrate some experience with at least some of these technologies, and willing to learn more and touch various different projects.</p>
<p>You will be part of a small team, so you will have an opportunity for a high-impact role, targeting hundreds of thousands of users.</p>
<p>If you're interested please contact us at job-AT-joplin.cloud</p>
<p>No agencies please.</p>
]]></description><link>https://joplinapp.org/news/20221209-job</link><guid isPermaLink="false">20221209-job</guid><pubDate>Fri, 09 Dec 2022 00:00:00 GMT</pubDate><twitter-text>Joplin is hiring!</twitter-text></item><item><title><![CDATA[Modernising and securing Joplin, one package at a time]]></title><description><![CDATA[<p>If you watch the <a href="https://github.com/laurent22/joplin">Joplin source code repository</a>, you may have noticed a lot of Renovate pull requests lately. This <a href="https://www.mend.io/free-developer-tools/renovate/">Renovate tool</a> is a way to manage dependencies - it automatically finds what needs to be updated, then upgrade it to the latest version, and create a pull request. If all tests pass, we can then merge this pull request. So far we have merged 267 of these pull requests.</p>
<p>Updating Joplin packages was long due. It is necessary so that we don't fall behind and end up using unsupported or deprecated packages. We also benefit from bug fixes and performance improvements. It is also important in terms of security, since recent package versions usually include various security fixes.</p>
<p>We used to rely on a tool called &quot;npm audit&quot; to do this, however it no longer works on the Joplin codebase, and it was always risky to use it since it would update multiple packages in one command - so if something went wrong it was difficult to find the culprit.</p>
<p>Renovate on the other hand upgrades packages one at a time, and run our test units to ensure everything is still working as expected. It also upgrades multiple instances of the same package across the monorepo, which is convenient to keep our code consistent. It also has a number of options to make our life easier, such as the ability to automatically merge a pull request for patch releases since this is usually safe (when a package is, for example upgraded from 1.0.1 to 1.0.3).</p>
<p>Although Renovate automates the package upgrades it doesn't mean all upgrades are straightforward - our tests won't catch all issues, so the apps might end up being broken or cannot be compiled anymore. So there's manual work involved to get everything working after certain upgrades - for the most part this has been done and the apps appear to be stable so far.</p>
<p>This will however be an important part of pre-release 2.10 (or should it be 3.0?) - we hope that everything works but we may need your support to try this version and report any glitch you may have found. As always pre-release regressions have the highest priority so we aim to fix them as quickly as possible.</p>
]]></description><link>https://joplinapp.org/news/20221115-renovate</link><guid isPermaLink="false">20221115-renovate</guid><pubDate>Tue, 15 Nov 2022 00:00:00 GMT</pubDate><twitter-text>Modernising and securing Joplin, one package at a time</twitter-text></item><item><title><![CDATA[Joplin Cloud is now part of the Joplin company]]></title><description><![CDATA[<p>As some of you may know Joplin Cloud so far has been operating under my own single-person limited company in the UK. This was mostly for convenience since it meant I could get things going quickly without having to setup a special structure for it.</p>
<p>Now that Joplin Cloud is becoming more mature however a proper company, simply called Joplin, has been created. This company will be based in France, and will be used mainly to handle the commercial part of the project, which currently is mostly Joplin Cloud. I'm still heading the company so there won't be any major change to the way the project is managed.</p>
<h2>What does it mean for Joplin Cloud?<a name="what-does-it-mean-for-joplin-cloud" href="#what-does-it-mean-for-joplin-cloud" class="heading-anchor">🔗</a></h2>
<p>There will be no significant change - the website ownership simply moves from one company in the UK to one in France. The new company is still owned by myself so I will keep following the same roadmap.</p>
<h2>What does it mean for the open source apps?<a name="what-does-it-mean-for-the-open-source-apps" href="#what-does-it-mean-for-the-open-source-apps" class="heading-anchor">🔗</a></h2>
<p>On the short term, the only visible change will be moving the non-open source assets, such as logo or trademark from the UK company to the French one. So expect a few changes in copyright notices here and there.</p>
<p>In the medium to long term, I would like to hire one or two software developers to help me with the Joplin Cloud development, because we reached a point where managing the whole project is difficult for a single person, so some help is needed. Some of their work might also touch the open source apps since both are quite related - but of course that work will remain open source too.</p>
<p>As a general rule, there will be a permanent commitment to keep the apps open source and to derive value from Joplin Cloud/Server.</p>
<p>Longer term I would like to create a non-profit organisation to handle the open source applications and to make decisions about the project, as well as to decide how to allocate any funding we receive (for example from GSoC).</p>
<h2>Looking forward<a name="looking-forward" href="#looking-forward" class="heading-anchor">🔗</a></h2>
<p>Those past 6 years of developing Joplin have been an exciting and rewarding experience, thank you to all of you of the friendly and vibrant Joplin community for your contribution toward making Joplin the software it is today, and looking forward to continuing the journey together!</p>
]]></description><link>https://joplinapp.org/news/20221012-Joplin-Company</link><guid isPermaLink="false">20221012-Joplin-Company</guid><pubDate>Wed, 12 Oct 2022 00:00:00 GMT</pubDate><twitter-text>Joplin Cloud is now operated by the Joplin company! More info on the announcement post.</twitter-text></item><item><title><![CDATA[Joplin interview on Website Planet]]></title><description><![CDATA[<p>Website Planet has recently conducted an interview about Joplin - it may give you some insight on the current status of the project, our priorities, and future plans! More on the article page - <a href="https://www.websiteplanet.com/blog/interview-joplin/">Organise Your Thoughts with Open Source Note-Taking App, Joplin</a></p>
]]></description><link>https://joplinapp.org/news/20220906-interview-websiteplanet</link><guid isPermaLink="false">20220906-interview-websiteplanet</guid><pubDate>Tue, 06 Sep 2022 00:00:00 GMT</pubDate><twitter-text></twitter-text></item><item><title><![CDATA[Joplin first meetup on 30 August!]]></title><description><![CDATA[<p>We are glad to announce <a href="https://www.meetup.com/joplin/events/287611873/">the first Joplin Meetup</a> that will take place on 30 August 2022 in London!</p>
<p>This is an opportunity to meet other Joplin users as well as some of the main contributors, to discuss the apps, or to ask questions and exchange tips and tricks on how to use the app, develop plugins or contribute to the application. Everybody, technical or not, is welcome!</p>
<p>We will meet at the Old Thameside Inn next to London Bridge. If the weather allows we will be on the terrace outside, if not inside.</p>
<p>More information on the official Meetup page:</p>
<p><a href="https://www.meetup.com/joplin/events/287611873/">https://www.meetup.com/joplin/events/287611873/</a></p>
]]></description><link>https://joplinapp.org/news/20220808-first-meetup</link><guid isPermaLink="false">20220808-first-meetup</guid><pubDate>Mon, 08 Aug 2022 00:00:00 GMT</pubDate><twitter-text>Joplin will have its first Meetup on 30 August! Come and join us at the Old Thameside Inn next to London Bridge! https://www.meetup.com/joplin/events/287611873/</twitter-text></item><item><title><![CDATA[Joplin 2.8 is available!]]></title><description><![CDATA[<p>As always a lot of changes and new features in this new version available on both desktop and mobile.</p>
<h2>Multiple profile support<a name="multiple-profile-support" href="#multiple-profile-support" class="heading-anchor">🔗</a></h2>
<p>Perhaps the most visible change in this version is the support for multiple profiles. You can now create as many application profile as you wish, each with their own settings, and easily switch from one to another. The main use case is to support for example a &quot;work&quot; profile and a &quot;personal&quot; profile, to allow you to keep things independent, and each profile can sync with a different sync target.</p>
<p>To create a new profile, open <strong>File &gt; Switch profile</strong> and select <strong>Create new profile</strong>, enter the profile name and press OK. The app will automatically switch to this new profile, which you can now configure.</p>
<p>To switch back to the previous profile, again open <strong>File &gt; Switch profile</strong> and select <strong>Default</strong>.</p>
<p>Note that profiles all share certain settings, such as language, font size, theme, etc. This is done so that you don't have reconfigure every details when switching profiles. Other settings such as sync configuration is per profile.</p>
<p>The feature is available on desktop only for now, and should be ported to mobile relatively soon.</p>
<h2>Save Mermaid graph as PNG/SVG<a name="save-mermaid-graph-as-png-svg" href="#save-mermaid-graph-as-png-svg" class="heading-anchor">🔗</a></h2>
<p>This convenient feature allows exporting a Mermaid graph as a PNG or SVG image, or allows copying the image as a DataUrl, which can then be pasted in any compatible text editor. Thanks Asrient for implementing this!</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20220606-mermaid-as-png.png" alt=""></p>
<h2>Publish a mini-website using Joplin Cloud<a name="publish-a-mini-website-using-joplin-cloud" href="#publish-a-mini-website-using-joplin-cloud" class="heading-anchor">🔗</a></h2>
<p>Joplin Cloud now supports publishing a note &quot;recursively&quot;, which means the notes and all the notes it is linked to. This allows easily publishing a simple website made of multiples and images.</p>
<p>To make use of this feature, simply select <strong>Also publish linked notes</strong> when publishing a note.</p>
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/news/20220606-publish-website.png" alt=""></p>
<h2>And more!<a name="and-more" href="#and-more" class="heading-anchor">🔗</a></h2>
<p>In total there are 38 changes to improve the app reliability, security and usability. Full changelog is at <a href="https://joplinapp.org/help/about/changelog/desktop">https://joplinapp.org/help/about/changelog/desktop</a></p>
]]></description><link>https://joplinapp.org/news/20220606-release-2-8</link><guid isPermaLink="false">20220606-release-2-8</guid><pubDate>Mon, 06 Jun 2022 00:00:00 GMT</pubDate><twitter-text></twitter-text></item></channel></rss>

View File

@@ -398,7 +398,7 @@
<div class="text-center sponsors-org">
{{#sponsors.orgs}}
<a class="sponsor-org-item" href="{{url}}"><img alt="{{alt}}" title="{{title}}" src="{{imageBaseUrl}}/sponsors/{{imageName}}"></a>
<a class="sponsor-org-item" href="{{url}}"><img title="{{title}}" src="{{imageBaseUrl}}/sponsors/{{imageName}}"></a>
{{/sponsors.orgs}}
</div>

View File

@@ -1,28 +1,24 @@
<div class="col-12 col-lg-4 account-type-{{priceMonthly.accountType}} hosting-type-{{hostingType}}">
<div class="col-12 col-lg-4 account-type-{{priceMonthly.accountType}}">
<div class="price-container {{#featured}}price-container-blue{{/featured}}">
<div class="price-row">
<div class="plan-type">
<img src="{{imageBaseUrl}}/{{iconName}}.png"/>&nbsp;{{title}}
</div>
{{#priceMonthly.formattedMonthlyAmount}}
<div class="plan-price plan-price-monthly">
{{priceMonthly.formattedMonthlyAmount}}<sub class="per-month">&nbsp;<span translate>/month</span>{{#footnote}} (*){{/footnote}}</sub>
</div>
<div class="plan-price plan-price-yearly">
{{priceYearly.formattedMonthlyAmount}}<sub class="per-month">&nbsp;<span translate>/month</span>{{#footnote}} (*){{/footnote}}</sub>
</div>
{{/priceMonthly.formattedMonthlyAmount}}
<div class="price-row">
<div class="plan-type">
<img src="{{imageBaseUrl}}/{{iconName}}.png"/>&nbsp;{{title}}
</div>
{{#priceYearly.formattedMonthlyAmount}}
<div class="plan-price-yearly-per-year">
<div>
({{priceYearly.formattedAmount}}<sub class="per-year">&nbsp;<span translate>/year</span></sub>)
</div>
<div class="plan-price plan-price-monthly">
{{priceMonthly.formattedMonthlyAmount}}<sub class="per-month">&nbsp;<span translate>/month</span>{{#footnote}} (*){{/footnote}}</sub>
</div>
{{/priceYearly.formattedMonthlyAmount}}
<div class="plan-price plan-price-yearly">
{{priceYearly.formattedMonthlyAmount}}<sub class="per-month">&nbsp;<span translate>/month</span>{{#footnote}} (*){{/footnote}}</sub>
</div>
</div>
<div class="plan-price-yearly-per-year">
<div>
({{priceYearly.formattedAmount}}<sub class="per-year">&nbsp;<span translate>/year</span></sub>)
</div>
</div>
{{#featureLabelsOn}}
<p><i class="fas fa-check feature feature-on"></i>{{.}}</p>
@@ -33,11 +29,7 @@
{{/featureLabelsOff}}
<p class="text-center subscribe-wrapper">
<a id="subscribeButton-{{name}}" href="{{cfaUrl}}" class="button-link btn-white subscribeButton cfa-button">{{cfaLabel}}</a>
{{#learnMoreUrl}}
<a id="learnMore-{{name}}" href="{{learnMoreUrl}}" class="button-link btn-white learnMoreButton cfa-button">Learn more</a>
{{/learnMoreUrl}}
<a id="subscribeButton-{{name}}" href="{{cfaUrl}}" class="button-link btn-white subscribeButton">{{cfaLabel}}</a>
</p>
{{#footnote}}<sub>(*) {{.}}</sub>{{/footnote}}

View File

@@ -1,6 +1,6 @@
<div class="row">
<div class="col-12 col-md-12 social-links">
<a class="social-link-bluesky" href="https://bsky.app/profile/joplinapp.bsky.social" title="Joplin Bluesky feed"><i class="fa-brands fa-bluesky"></i></a>
<a class="social-link-twitter" href="https://twitter.com/joplinapp" title="Joplin Twitter feed"><i class="fab fa-twitter"></i></a>
<a class="social-link-mastodon" href="https://mastodon.social/@joplinapp" title="Joplin Mastodon feed"><i class="fab fa-mastodon"></i></a>
<a class="social-link-patreon" href="https://www.patreon.com/joplin" title="Joplin Patreon"><i class="fab fa-patreon"></i></a>
<a class="social-link-discord" href="https://discord.gg/VSj7AFHvpq" title="Joplin Discord chat"><i class="fab fa-discord"></i></a>
@@ -8,4 +8,4 @@
<a class="social-link-lemmy" href="https://sopuli.xyz/c/joplinapp" title="Joplin Lemmy Community"><i class="fas fa-otter"></i></a>
<a class="social-link-github" href="https://github.com/laurent22/joplin/" title="Joplin GitHub repository"><i class="fab fa-github"></i></a>
</div>
</div>
</div>

View File

@@ -1 +1 @@
<a href="https://bsky.app/profile/joplinapp.bsky.social" title="Joplin Bluesky feed" class="fw500 twitter-link"><i class="fa-brands fa-bluesky"></i></a>
<a href="https://twitter.com/joplinapp" title="Joplin Twitter feed" class="fw500 twitter-link"><i class="fab fa-twitter"></i></a>

View File

@@ -1,91 +1,23 @@
<div id="plans-section" class="env-{{env}}">
<style>
.toggle-container {
display: flex;
border: 2px solid black;
border-radius: 100px;
overflow: hidden;
cursor: pointer;
margin-top: 20px;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.toggle-option {
flex: 1;
padding: 10px 20px;
text-align: center;
transition: background 0.3s, color 0.3s;
user-select: none;
white-space: nowrap;
}
.active {
background: black;
color: white;
}
.inactive {
background: white;
color: black;
}
@media (max-width: 480px) {
.toggle-container {
flex-direction: column;
width: 100%;
border-radius: 10px;
}
}
</style>
<div class="container">
<div class="row">
<div class="col-12 title-box">
<h1 translate class="text-center">
Our synchronisation and sharing <span class="frame-bg frame-bg-yellow">solutions</span>
Joplin Cloud <span class="frame-bg frame-bg-yellow">plans</span>
</h1>
<p translate class="text-center sub-title">
Synchronise and share your notes with our range of plans.
<a href="https://joplincloud.com">Joplin Cloud</a> allows you to synchronise your notes across devices. It also lets you publish notes, and collaborate on notebooks with your friends, family or colleagues.
</p>
</div>
</div>
<div class="toggle-container" id="toggle">
<div class="toggle-option active toggle-button-managed">Managed hosting</div>
<div class="toggle-option inactive toggle-button-self">Self-hosting</div>
</div>
<noscript>
<div class="alert alert-danger alert-env-dev" role="alert" style='text-align: center; margin-top: 10px;'>
To use this page please enable JavaScript!
</div>
</noscript>
<div class="row hosting-type-managed">
<div class="col-12 title-box">
<h1 translate class="text-center">
Joplin Cloud
</h1>
<p translate class="text-center sub-title">
<a href="https://joplincloud.com">Joplin Cloud</a> allows you to synchronise your notes across devices. It also lets you publish notes, and collaborate on notebooks with your friends, family or colleagues.
</p>
</div>
</div>
<div class="row hosting-type-self">
<div class="col-12 title-box">
<h1 translate class="text-center">
Joplin Server Business
</h1>
<p translate class="text-center sub-title">
Joplin Server Business is a synchronisation server that you can install on your own infrastructure, so that your data remains private and secure within your business.
</p>
</div>
</div>
<div style="display: flex; justify-content: center; margin-top: 1.2em" class="hosting-type-managed">
<div style="display: flex; justify-content: center; margin-top: 1.2em">
<div class="form-check form-check-inline">
<input id="pay-monthly-radio" class="form-check-input" type="radio" name="pay-radio" checked value="monthly">
<label translate style="font-weight: bold" class="form-check-label" for="pay-monthly-radio">
@@ -114,11 +46,7 @@
{{> plan}}
{{/plans.teams}}
{{#plans.joplinServerBusiness}}
{{> plan}}
{{/plans.joplinServerBusiness}}
<p translate class="joplin-cloud-login-info hosting-type-managed">Already have a Joplin Cloud account? <a href="https://joplincloud.com">Login now</a></p>
<p translate class="joplin-cloud-login-info">Already have a Joplin Cloud account? <a href="https://joplincloud.com">Login now</a></p>
</div>
<div class="row">
@@ -219,29 +147,5 @@
$('.feature-description-' + featureId).toggle(200);
});
});
const setHostingType = (type) => {
const other = type === 'managed' ? 'self' : 'managed';
$('.toggle-button-' + type).addClass('active');
$('.toggle-button-' + type).removeClass('inactive');
$('.toggle-button-' + other).addClass('inactive');
$('.toggle-button-' + other).removeClass('active');
$('.hosting-type-' + type).show();
$('.hosting-type-' + other).hide();
}
$('.toggle-button-managed').click((event) => {
event.preventDefault();
setHostingType('managed');
});
$('.toggle-button-self').click((event) => {
event.preventDefault();
setHostingType('self');
});
const initialHostingType = urlQuery.get('hosting') ? urlQuery.get('hosting') : 'managed';
setHostingType(initialHostingType);
</script>
</div>

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 730 KiB

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More