From 4b588b90aa783a00dcff9cb94621aab75341b187 Mon Sep 17 00:00:00 2001 From: DrKLO Date: Thu, 24 Dec 2020 09:36:01 +0400 Subject: [PATCH] Update to 7.3.0 (2196) --- Dockerfile | 2 +- TMessagesProj/build.gradle | 2 +- TMessagesProj/jni/sqlite/sqlite3.c | 2677 ++++++++++++----- TMessagesProj/jni/sqlite/sqlite3.h | 79 +- .../org_telegram_messenger_voip_Instance.cpp | 55 +- .../platform/android/AndroidContext.cpp | 16 +- .../tgcalls/platform/android/AndroidContext.h | 6 +- .../jni/voip/webrtc/api/video/i420_buffer.cc | 13 +- .../widget/ChatListItemAnimator.java | 2 +- .../org/telegram/messenger/BuildVars.java | 2 +- .../org/telegram/messenger/ImageLoader.java | 2 +- .../messenger/MediaDataController.java | 6 +- .../telegram/messenger/MessagesStorage.java | 3 +- .../messenger/NotificationCenter.java | 92 +- .../messenger/NotificationsController.java | 14 +- .../NotificationsDisabledReceiver.java | 15 +- .../org/telegram/messenger/SvgHelper.java | 17 +- .../messenger/voip/VoIPBaseService.java | 9 +- .../telegram/messenger/voip/VoIPService.java | 17 +- .../ui/ActionBar/ActionBarMenuItem.java | 11 +- .../ui/ActionBar/AdjustPanLayoutHelper.java | 5 +- .../java/org/telegram/ui/ArticleViewer.java | 2 +- .../org/telegram/ui/CacheControlActivity.java | 2 +- .../ui/CancelAccountDeletionActivity.java | 2 +- .../ui/Cells/SharingLiveLocationCell.java | 2 +- .../org/telegram/ui/ChangeNameActivity.java | 2 +- .../org/telegram/ui/ChangePhoneActivity.java | 2 +- .../telegram/ui/ChangeUsernameActivity.java | 2 +- .../telegram/ui/ChannelAdminLogActivity.java | 1 + .../telegram/ui/ChannelCreateActivity.java | 2 +- .../java/org/telegram/ui/ChatActivity.java | 179 +- .../org/telegram/ui/ChatEditTypeActivity.java | 2 +- .../org/telegram/ui/ChatLinkActivity.java | 2 +- .../org/telegram/ui/ChatUsersActivity.java | 15 + .../ChatAttachAlertLocationLayout.java | 2 +- .../ui/Components/ChatAvatarContainer.java | 28 +- .../ui/Components/FragmentContextView.java | 4 - .../telegram/ui/Components/GroupCallPip.java | 5 + .../ui/Components/PhotoPaintView.java | 5 + .../ui/Components/SearchViewPager.java | 4 +- .../ui/Components/voip/VoIPToggleButton.java | 73 +- .../ui/Components/voip/VoIPWindowView.java | 5 +- .../org/telegram/ui/ContactsActivity.java | 10 +- .../java/org/telegram/ui/DialogsActivity.java | 61 +- .../org/telegram/ui/FilteredSearchView.java | 3 +- .../org/telegram/ui/GroupCreateActivity.java | 42 +- .../telegram/ui/GroupStickersActivity.java | 2 +- .../java/org/telegram/ui/LaunchActivity.java | 4 +- .../org/telegram/ui/LocationActivity.java | 10 +- .../org/telegram/ui/PasscodeActivity.java | 2 +- .../org/telegram/ui/PassportActivity.java | 2 +- .../org/telegram/ui/PaymentFormActivity.java | 2 +- .../org/telegram/ui/PhotoCropActivity.java | 2 +- .../java/org/telegram/ui/PhotoViewer.java | 17 +- .../telegram/ui/PrivacyControlActivity.java | 2 +- .../java/org/telegram/ui/ProfileActivity.java | 61 +- .../org/telegram/ui/ReportOtherActivity.java | 2 +- .../ui/TwoStepVerificationActivity.java | 2 +- .../ui/TwoStepVerificationSetupActivity.java | 11 +- .../java/org/telegram/ui/VoIPFragment.java | 4 - .../telegram/ui/WallpapersListActivity.java | 4 +- .../src/main/res/values-ar/strings.xml | 366 ++- .../src/main/res/values-de/strings.xml | 186 +- .../src/main/res/values-es/strings.xml | 270 +- .../src/main/res/values-it/strings.xml | 290 +- .../src/main/res/values-ko/strings.xml | 532 ++-- .../src/main/res/values-nl/strings.xml | 600 ++-- .../src/main/res/values-pt-rBR/strings.xml | 246 +- TMessagesProj/src/main/res/values/strings.xml | 2 + 69 files changed, 4280 insertions(+), 1841 deletions(-) diff --git a/Dockerfile b/Dockerfile index b449368dd98..011f3992919 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,4 +24,4 @@ RUN $ANDROID_HOME/tools/bin/sdkmanager "build-tools;${ANDROID_BUILD_TOOLS_VERSIO ENV PATH ${ANDROID_NDK_HOME}:$PATH ENV PATH ${ANDROID_NDK_HOME}/prebuilt/linux-x86_64/bin/:$PATH -CMD mkdir -p /home/source/TMessagesProj/build/outputs/apk && mkdir -p /home/source/TMessagesProj/build/intermediates/ndkBuild && cp -R /home/source/. /home/gradle && cd /home/gradle && gradle assembleRelease && cp -R /home/gradle/TMessagesProj/build/outputs/apk/. /home/source/TMessagesProj/build/outputs/apk && cp -R /home/gradle/TMessagesProj/build/intermediates/ndkBuild/. /home/source/TMessagesProj/build/intermediates/ndkBuild +CMD mkdir -p /home/source/TMessagesProj/build/outputs/apk && mkdir -p /home/source/TMessagesProj/build/outputs/native-debug-symbols && cp -R /home/source/. /home/gradle && cd /home/gradle && gradle assembleRelease && cp -R /home/gradle/TMessagesProj/build/outputs/apk/. /home/source/TMessagesProj/build/outputs/apk && cp -R /home/gradle/TMessagesProj/build/outputs/native-debug-symbols/. /home/source/TMessagesProj/build/outputs/native-debug-symbols diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 3fb8cbc5ed0..6930b5c4ef1 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -290,7 +290,7 @@ android { } } - defaultConfig.versionCode = 2195 + defaultConfig.versionCode = 2196 applicationVariants.all { variant -> variant.outputs.all { output -> diff --git a/TMessagesProj/jni/sqlite/sqlite3.c b/TMessagesProj/jni/sqlite/sqlite3.c index 8b4577776c4..a402fcae5ec 100644 --- a/TMessagesProj/jni/sqlite/sqlite3.c +++ b/TMessagesProj/jni/sqlite/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.33.0. By combining all the individual C code files into this +** version 3.34.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -1171,9 +1171,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.33.0" -#define SQLITE_VERSION_NUMBER 3033000 -#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f" +#define SQLITE_VERSION "3.34.0" +#define SQLITE_VERSION_NUMBER 3034000 +#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -1552,6 +1552,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) +#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) @@ -7234,6 +7235,57 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); +/* +** CAPI3REF: Determine the transaction state of a database +** METHOD: sqlite3 +** +** ^The sqlite3_txn_state(D,S) interface returns the current +** [transaction state] of schema S in database connection D. ^If S is NULL, +** then the highest transaction state of any schema on database connection D +** is returned. Transaction states are (in order of lowest to highest): +**
    +**
  1. SQLITE_TXN_NONE +**
  2. SQLITE_TXN_READ +**
  3. SQLITE_TXN_WRITE +**
+** ^If the S argument to sqlite3_txn_state(D,S) is not the name of +** a valid schema, then -1 is returned. +*/ +SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); + +/* +** CAPI3REF: Allowed return values from [sqlite3_txn_state()] +** KEYWORDS: {transaction state} +** +** These constants define the current transaction state of a database file. +** ^The [sqlite3_txn_state(D,S)] interface returns one of these +** constants in order to describe the transaction state of schema S +** in [database connection] D. +** +**
+** [[SQLITE_TXN_NONE]]
SQLITE_TXN_NONE
+**
The SQLITE_TXN_NONE state means that no transaction is currently +** pending.
+** +** [[SQLITE_TXN_READ]]
SQLITE_TXN_READ
+**
The SQLITE_TXN_READ state means that the database is currently +** in a read transaction. Content has been read from the database file +** but nothing in the database file has changed. The transaction state +** will advanced to SQLITE_TXN_WRITE if any changes occur and there are +** no other conflicting concurrent write transactions. The transaction +** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or +** [COMMIT].
+** +** [[SQLITE_TXN_WRITE]]
SQLITE_TXN_WRITE
+**
The SQLITE_TXN_WRITE state means that the database is currently +** in a write transaction. Content has been written to the database file +** but has not yet committed. The transaction state will change to +** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
+*/ +#define SQLITE_TXN_NONE 0 +#define SQLITE_TXN_READ 1 +#define SQLITE_TXN_WRITE 2 + /* ** CAPI3REF: Find the next prepared statement ** METHOD: sqlite3 @@ -8760,7 +8812,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_RESULT_INTREAL 27 #define SQLITE_TESTCTRL_PRNG_SEED 28 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 -#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_SEEK_COUNT 30 +#define SQLITE_TESTCTRL_LAST 30 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -10240,10 +10293,11 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** ** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] -** method of a [virtual table], then it returns true if and only if the +** method of a [virtual table], then it might return true if the ** column is being fetched as part of an UPDATE operation during which the -** column value will not change. Applications might use this to substitute -** a return value that is less expensive to compute and that the corresponding +** column value will not change. The virtual table implementation can use +** this hint as permission to substitute a return value that is less +** expensive to compute and that the corresponding ** [xUpdate] method understands as a "no-change" value. ** ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that @@ -10252,6 +10306,12 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. ** In that case, [sqlite3_value_nochange(X)] will return true for the ** same column in the [xUpdate] method. +** +** The sqlite3_vtab_nochange() routine is an optimization. Virtual table +** implementations should continue to give a correct answer even if the +** sqlite3_vtab_nochange() interface were to always return false. In the +** current implementation, the sqlite3_vtab_nochange() interface does always +** returns false for the enhanced [UPDATE FROM] statement. */ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); @@ -10393,6 +10453,7 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction +** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the ** [sqlite3_db_cacheflush(D)] interface invoked, any dirty @@ -10425,6 +10486,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); /* ** CAPI3REF: The pre-update hook. +** METHOD: sqlite3 ** ** ^These interfaces are only available if SQLite is compiled using the ** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. @@ -10465,7 +10527,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for -** INSERT operations on rowid tables. +** DELETE operations on rowid tables. ** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces @@ -10527,6 +10589,7 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); /* ** CAPI3REF: Low-level system error code +** METHOD: sqlite3 ** ** ^Attempt to return the underlying operating system error code or error ** number that caused the most recent I/O error or failure to open a file. @@ -13297,11 +13360,7 @@ struct fts5_api { ** The maximum depth of an expression tree. This is limited to ** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might ** want to place more severe limits on the complexity of an -** expression. -** -** A value of 0 used to mean that the limit was not enforced. -** But that is no longer true. The limit is now strictly enforced -** at all times. +** expression. A value of 0 means that there is no limit. */ #ifndef SQLITE_MAX_EXPR_DEPTH # define SQLITE_MAX_EXPR_DEPTH 1000 @@ -15082,16 +15141,24 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int); SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags); -SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*); -SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*); +SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*); + SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree); #ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock); #endif + +/* Savepoints are named, nestable SQL transactions mostly implemented */ +/* in vdbe.c and pager.c See https://sqlite.org/lang_savepoint.html */ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int); +/* "Checkpoint" only refers to WAL. See https://sqlite.org/wal.html#ckpt */ +#ifndef SQLITE_OMIT_WAL +SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); +#endif + SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *); SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *); @@ -15328,6 +15395,12 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask); SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt); SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void); +#ifdef SQLITE_DEBUG +SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree*); +#else +# define sqlite3BtreeSeekCount(X) 0 +#endif + #ifndef NDEBUG SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*); #endif @@ -15681,64 +15754,65 @@ typedef struct VdbeOpList VdbeOpList; #define OP_String8 115 /* same as TK_STRING, synopsis: r[P2]='P4' */ #define OP_Close 116 #define OP_ColumnsUsed 117 -#define OP_SeekHit 118 /* synopsis: seekHit=P2 */ -#define OP_Sequence 119 /* synopsis: r[P2]=cursor[P1].ctr++ */ -#define OP_NewRowid 120 /* synopsis: r[P2]=rowid */ -#define OP_Insert 121 /* synopsis: intkey=r[P3] data=r[P2] */ -#define OP_Delete 122 -#define OP_ResetCount 123 -#define OP_SorterCompare 124 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ -#define OP_SorterData 125 /* synopsis: r[P2]=data */ -#define OP_RowData 126 /* synopsis: r[P2]=data */ -#define OP_Rowid 127 /* synopsis: r[P2]=rowid */ -#define OP_NullRow 128 -#define OP_SeekEnd 129 -#define OP_IdxInsert 130 /* synopsis: key=r[P2] */ -#define OP_SorterInsert 131 /* synopsis: key=r[P2] */ -#define OP_IdxDelete 132 /* synopsis: key=r[P2@P3] */ -#define OP_DeferredSeek 133 /* synopsis: Move P3 to P1.rowid if needed */ -#define OP_IdxRowid 134 /* synopsis: r[P2]=rowid */ -#define OP_FinishSeek 135 -#define OP_Destroy 136 -#define OP_Clear 137 -#define OP_ResetSorter 138 -#define OP_CreateBtree 139 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ -#define OP_SqlExec 140 -#define OP_ParseSchema 141 -#define OP_LoadAnalysis 142 -#define OP_DropTable 143 -#define OP_DropIndex 144 -#define OP_DropTrigger 145 -#define OP_IntegrityCk 146 -#define OP_RowSetAdd 147 /* synopsis: rowset(P1)=r[P2] */ -#define OP_Param 148 -#define OP_FkCounter 149 /* synopsis: fkctr[P1]+=P2 */ +#define OP_SeekScan 118 /* synopsis: Scan-ahead up to P1 rows */ +#define OP_SeekHit 119 /* synopsis: set P2<=seekHit<=P3 */ +#define OP_Sequence 120 /* synopsis: r[P2]=cursor[P1].ctr++ */ +#define OP_NewRowid 121 /* synopsis: r[P2]=rowid */ +#define OP_Insert 122 /* synopsis: intkey=r[P3] data=r[P2] */ +#define OP_Delete 123 +#define OP_ResetCount 124 +#define OP_SorterCompare 125 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */ +#define OP_SorterData 126 /* synopsis: r[P2]=data */ +#define OP_RowData 127 /* synopsis: r[P2]=data */ +#define OP_Rowid 128 /* synopsis: r[P2]=rowid */ +#define OP_NullRow 129 +#define OP_SeekEnd 130 +#define OP_IdxInsert 131 /* synopsis: key=r[P2] */ +#define OP_SorterInsert 132 /* synopsis: key=r[P2] */ +#define OP_IdxDelete 133 /* synopsis: key=r[P2@P3] */ +#define OP_DeferredSeek 134 /* synopsis: Move P3 to P1.rowid if needed */ +#define OP_IdxRowid 135 /* synopsis: r[P2]=rowid */ +#define OP_FinishSeek 136 +#define OP_Destroy 137 +#define OP_Clear 138 +#define OP_ResetSorter 139 +#define OP_CreateBtree 140 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ +#define OP_SqlExec 141 +#define OP_ParseSchema 142 +#define OP_LoadAnalysis 143 +#define OP_DropTable 144 +#define OP_DropIndex 145 +#define OP_DropTrigger 146 +#define OP_IntegrityCk 147 +#define OP_RowSetAdd 148 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 149 #define OP_Real 150 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_MemMax 151 /* synopsis: r[P1]=max(r[P1],r[P2]) */ -#define OP_OffsetLimit 152 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggInverse 153 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ -#define OP_AggStep 154 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep1 155 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggValue 156 /* synopsis: r[P3]=value N=P2 */ -#define OP_AggFinal 157 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 158 -#define OP_CursorLock 159 -#define OP_CursorUnlock 160 -#define OP_TableLock 161 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 162 -#define OP_VCreate 163 -#define OP_VDestroy 164 -#define OP_VOpen 165 -#define OP_VColumn 166 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 167 -#define OP_Pagecount 168 -#define OP_MaxPgcnt 169 -#define OP_Trace 170 -#define OP_CursorHint 171 -#define OP_ReleaseReg 172 /* synopsis: release r[P1@P2] mask P3 */ -#define OP_Noop 173 -#define OP_Explain 174 -#define OP_Abortable 175 +#define OP_FkCounter 151 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 152 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 153 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggInverse 154 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ +#define OP_AggStep 155 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep1 156 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggValue 157 /* synopsis: r[P3]=value N=P2 */ +#define OP_AggFinal 158 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 159 +#define OP_CursorLock 160 +#define OP_CursorUnlock 161 +#define OP_TableLock 162 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 163 +#define OP_VCreate 164 +#define OP_VDestroy 165 +#define OP_VOpen 166 +#define OP_VColumn 167 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 168 +#define OP_Pagecount 169 +#define OP_MaxPgcnt 170 +#define OP_Trace 171 +#define OP_CursorHint 172 +#define OP_ReleaseReg 173 /* synopsis: release r[P1@P2] mask P3 */ +#define OP_Noop 174 +#define OP_Explain 175 +#define OP_Abortable 176 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -15765,15 +15839,15 @@ typedef struct VdbeOpList VdbeOpList; /* 88 */ 0x20, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\ /* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, 0x26,\ /* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\ -/* 112 */ 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\ -/* 120 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ -/* 128 */ 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x00,\ -/* 136 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ -/* 144 */ 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x10, 0x04,\ -/* 152 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 112 */ 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ +/* 120 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 128 */ 0x10, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10,\ +/* 136 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\ +/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x10, 0x00,\ +/* 152 */ 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 168 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -} +/* 168 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 176 */ 0x00,} /* The sqlite3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum @@ -17550,6 +17624,7 @@ struct Table { #define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */ #define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */ #define TF_Shadow 0x1000 /* True for a shadow table */ +#define TF_HasStat4 0x2000 /* STAT4 info available for this table */ /* ** Test to see whether or not a table is a virtual table. This is @@ -18078,7 +18153,7 @@ struct Expr { #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ #define EP_Win 0x008000 /* Contains window functions */ #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ - /* 0x020000 // available for reuse */ +#define EP_IfNullRow 0x020000 /* The TK_IF_NULL_ROW opcode */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ #define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ @@ -18316,9 +18391,9 @@ struct SrcList { #define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */ #define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */ #define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */ -#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */ + /* 0x0400 not currently used */ #define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */ -#define WHERE_SEEK_UNIQ_TABLE 0x1000 /* Do not defer seeks if unique */ + /* 0x1000 not currently used */ /* 0x2000 not currently used */ #define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */ /* 0x8000 not currently used */ @@ -18515,9 +18590,6 @@ struct Select { ** statements within triggers whose only purpose is ** the side-effects of functions. ** -** All of the above are free to ignore their ORDER BY clause. Those that -** follow must honor the ORDER BY clause. -** ** SRT_Output Generate a row of output (using the OP_ResultRow ** opcode) for each row in the result set. ** @@ -18574,13 +18646,18 @@ struct Select { #define SRT_Except 2 /* Remove result from a UNION index */ #define SRT_Exists 3 /* Store 1 if the result is not empty */ #define SRT_Discard 4 /* Do not save the results anywhere */ -#define SRT_Fifo 5 /* Store result as data with an automatic rowid */ -#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */ +#define SRT_DistFifo 5 /* Like SRT_Fifo, but unique results only */ +#define SRT_DistQueue 6 /* Like SRT_Queue, but unique results only */ + +/* The DISTINCT clause is ignored for all of the above. Not that +** IgnorableDistinct() implies IgnorableOrderby() */ +#define IgnorableDistinct(X) ((X->eDest)<=SRT_DistQueue) + #define SRT_Queue 7 /* Store result in an queue */ -#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */ +#define SRT_Fifo 8 /* Store result as data with an automatic rowid */ /* The ORDER BY clause is ignored for all of the above */ -#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue) +#define IgnorableOrderby(X) ((X->eDest)<=SRT_Fifo) #define SRT_Output 9 /* Output each row of result */ #define SRT_Mem 10 /* Store result in a memory cell */ @@ -19547,7 +19624,7 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*); SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*); SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int); SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); -SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*); +SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*); SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*); @@ -20795,7 +20872,7 @@ struct VdbeCursor { Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ - Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */ + u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */ Btree *pBtx; /* Separate file holding temporary table */ i64 seqCount; /* Sequence counter */ u32 *aAltMap; /* Mapping from table to index column numbers */ @@ -27791,12 +27868,17 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ if( nOld==nNew ){ pNew = pOld; }else if( sqlite3GlobalConfig.bMemstat ){ + sqlite3_int64 nUsed; sqlite3_mutex_enter(mem0.mutex); sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes); nDiff = nNew - nOld; - if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= + if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); + if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){ + sqlite3_mutex_leave(mem0.mutex); + return 0; + } } pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT @@ -28103,12 +28185,15 @@ SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){ } /* -** Take actions at the end of an API call to indicate an OOM error +** Take actions at the end of an API call to deal with error codes. */ -static SQLITE_NOINLINE int apiOomError(sqlite3 *db){ - sqlite3OomClear(db); - sqlite3Error(db, SQLITE_NOMEM); - return SQLITE_NOMEM_BKPT; +static SQLITE_NOINLINE int apiHandleError(sqlite3 *db, int rc){ + if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ + sqlite3OomClear(db); + sqlite3Error(db, SQLITE_NOMEM); + return SQLITE_NOMEM_BKPT; + } + return rc & db->errMask; } /* @@ -28130,8 +28215,8 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){ */ assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); - if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ - return apiOomError(db); + if( db->mallocFailed || rc ){ + return apiHandleError(db, rc); } return rc & db->errMask; } @@ -28567,11 +28652,10 @@ SQLITE_API void sqlite3_str_vappendf( v = va_arg(ap,int); } if( v<0 ){ - if( v==SMALLEST_INT64 ){ - longvalue = ((u64)1)<<63; - }else{ - longvalue = -v; - } + testcase( v==SMALLEST_INT64 ); + testcase( v==(-1) ); + longvalue = ~v; + longvalue++; prefix = '-'; }else{ longvalue = v; @@ -31867,6 +31951,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc incr = 1; }else{ incr = 2; + length &= ~1; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); for(i=3-enc; i0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 153 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), - /* 154 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 155 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 156 */ "AggValue" OpHelp("r[P3]=value N=P2"), - /* 157 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 158 */ "Expire" OpHelp(""), - /* 159 */ "CursorLock" OpHelp(""), - /* 160 */ "CursorUnlock" OpHelp(""), - /* 161 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 162 */ "VBegin" OpHelp(""), - /* 163 */ "VCreate" OpHelp(""), - /* 164 */ "VDestroy" OpHelp(""), - /* 165 */ "VOpen" OpHelp(""), - /* 166 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 167 */ "VRename" OpHelp(""), - /* 168 */ "Pagecount" OpHelp(""), - /* 169 */ "MaxPgcnt" OpHelp(""), - /* 170 */ "Trace" OpHelp(""), - /* 171 */ "CursorHint" OpHelp(""), - /* 172 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), - /* 173 */ "Noop" OpHelp(""), - /* 174 */ "Explain" OpHelp(""), - /* 175 */ "Abortable" OpHelp(""), + /* 151 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 152 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 153 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 154 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), + /* 155 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 156 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 157 */ "AggValue" OpHelp("r[P3]=value N=P2"), + /* 158 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 159 */ "Expire" OpHelp(""), + /* 160 */ "CursorLock" OpHelp(""), + /* 161 */ "CursorUnlock" OpHelp(""), + /* 162 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 163 */ "VBegin" OpHelp(""), + /* 164 */ "VCreate" OpHelp(""), + /* 165 */ "VDestroy" OpHelp(""), + /* 166 */ "VOpen" OpHelp(""), + /* 167 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 168 */ "VRename" OpHelp(""), + /* 169 */ "Pagecount" OpHelp(""), + /* 170 */ "MaxPgcnt" OpHelp(""), + /* 171 */ "Trace" OpHelp(""), + /* 172 */ "CursorHint" OpHelp(""), + /* 173 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), + /* 174 */ "Noop" OpHelp(""), + /* 175 */ "Explain" OpHelp(""), + /* 176 */ "Abortable" OpHelp(""), }; return azName[i]; } @@ -33472,7 +33558,8 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ # if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \ (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000)) # if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \ - && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0)) + && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))\ + && (!defined(TARGET_OS_MACCATALYST) || (TARGET_OS_MACCATALYST==0)) # undef HAVE_GETHOSTUUID # define HAVE_GETHOSTUUID 1 # else @@ -35092,6 +35179,9 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ return rc; } +/* Forward declaration*/ +static int unixSleep(sqlite3_vfs*,int); + /* ** Set a posix-advisory-lock. ** @@ -35121,7 +35211,7 @@ static int osSetPosixAdvisoryLock( ** generic posix, however, there is no such API. So we simply try the ** lock once every millisecond until either the timeout expires, or until ** the lock is obtained. */ - usleep(1000); + unixSleep(0,1000); rc = osFcntl(h,F_SETLK,pLock); tm--; } @@ -35692,6 +35782,7 @@ static int unixClose(sqlite3_file *id){ } sqlite3_mutex_leave(pInode->pLockMutex); releaseInodeInfo(pFile); + assert( pFile->pShm==0 ); rc = closeUnixFile(id); unixLeaveMutex(); return rc; @@ -36918,7 +37009,24 @@ static int unixRead( if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ - /* lastErrno set by seekAndRead */ + /* pFile->lastErrno has been set by seekAndRead(). + ** Usually we return SQLITE_IOERR_READ here, though for some + ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The + ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT + ** prior to returning to the application by the sqlite3ApiExit() + ** routine. + */ + switch( pFile->lastErrno ){ + case ERANGE: + case EIO: +#ifdef ENXIO + case ENXIO: +#endif +#ifdef EDEVERR + case EDEVERR: +#endif + return SQLITE_IOERR_CORRUPTFS; + } return SQLITE_IOERR_READ; }else{ storeLastErrno(pFile, 0); /* not a system error */ @@ -37802,6 +37910,7 @@ struct unixShmNode { char **apRegion; /* Array of mapped shared-memory regions */ int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ + int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */ #ifdef SQLITE_DEBUG u8 exclMask; /* Mask of exclusive locks held */ u8 sharedMask; /* Mask of shared locks held */ @@ -38342,6 +38451,38 @@ static int unixShmMap( return rc; } +/* +** Check that the pShmNode->aLock[] array comports with the locking bitmasks +** held by each client. Return true if it does, or false otherwise. This +** is to be used in an assert(). e.g. +** +** assert( assertLockingArrayOk(pShmNode) ); +*/ +#ifdef SQLITE_DEBUG +static int assertLockingArrayOk(unixShmNode *pShmNode){ + unixShm *pX; + int aLock[SQLITE_SHM_NLOCK]; + assert( sqlite3_mutex_held(pShmNode->pShmMutex) ); + + memset(aLock, 0, sizeof(aLock)); + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ + int i; + for(i=0; iexclMask & (1<sharedMask & (1<=0 ); + aLock[i]++; + } + } + } + + assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) ); + return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0); +} +#endif + /* ** Change the lock state for a shared-memory segment. ** @@ -38358,10 +38499,10 @@ static int unixShmLock( ){ unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */ unixShm *p = pDbFd->pShm; /* The shared memory being locked */ - unixShm *pX; /* For looping over all siblings */ unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ + int *aLock = pShmNode->aLock; assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); @@ -38400,78 +38541,76 @@ static int unixShmLock( mask = (1<<(ofst+n)) - (1<1 || mask==(1<pShmMutex); + assert( assertLockingArrayOk(pShmNode) ); if( flags & SQLITE_SHM_UNLOCK ){ - u16 allMask = 0; /* Mask of locks held by siblings */ + if( (p->exclMask|p->sharedMask) & mask ){ + int ii; + int bUnlock = 1; - /* See if any siblings hold this same lock */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( pX==p ) continue; - assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); - allMask |= pX->sharedMask; - } + for(ii=ofst; ii((p->sharedMask & (1<sharedMask & (1<1 ); + aLock[ofst]--; + } - /* Undo the local locks */ - if( rc==SQLITE_OK ){ - p->exclMask &= ~mask; - p->sharedMask &= ~mask; + /* Undo the local locks */ + if( rc==SQLITE_OK ){ + p->exclMask &= ~mask; + p->sharedMask &= ~mask; + } } }else if( flags & SQLITE_SHM_SHARED ){ - u16 allShared = 0; /* Union of locks held by connections other than "p" */ - - /* Find out which shared locks are already held by sibling connections. - ** If any sibling already holds an exclusive lock, go ahead and return - ** SQLITE_BUSY. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 ){ + assert( n==1 ); + assert( (p->exclMask & (1<sharedMask & mask)==0 ){ + if( aLock[ofst]<0 ){ rc = SQLITE_BUSY; - break; - } - allShared |= pX->sharedMask; - } - - /* Get shared locks at the system level, if necessary */ - if( rc==SQLITE_OK ){ - if( (allShared & mask)==0 ){ + }else if( aLock[ofst]==0 ){ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); - }else{ - rc = SQLITE_OK; } - } - /* Get the local shared locks */ - if( rc==SQLITE_OK ){ - p->sharedMask |= mask; + /* Get the local shared locks */ + if( rc==SQLITE_OK ){ + p->sharedMask |= mask; + aLock[ofst]++; + } } }else{ /* Make sure no sibling connections hold locks that will block this - ** lock. If any do, return SQLITE_BUSY right away. - */ - for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ - if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ + ** lock. If any do, return SQLITE_BUSY right away. */ + int ii; + for(ii=ofst; iisharedMask & mask)==0 ); + if( ALWAYS((p->exclMask & (1<sharedMask & mask)==0 ); p->exclMask |= mask; + for(ii=ofst; iipShmMutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); @@ -39848,7 +39987,26 @@ static int unixAccess( } /* +** If the last component of the pathname in z[0]..z[j-1] is something +** other than ".." then back it out and return true. If the last +** component is empty or if it is ".." then return false. +*/ +static int unixBackupDir(const char *z, int *pJ){ + int j = *pJ; + int i; + if( j<=0 ) return 0; + for(i=j-1; ALWAYS(i>0) && z[i-1]!='/'; i--){} + if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; + *pJ = i-1; + return 1; +} + +/* +** Convert a relative pathname into a full pathname. Also +** simplify the pathname as follows: ** +** Remove all instances of /./ +** Remove all isntances of /X/../ for any X */ static int mkFullPathname( const char *zPath, /* Input path */ @@ -39857,6 +40015,7 @@ static int mkFullPathname( ){ int nPath = sqlite3Strlen30(zPath); int iOff = 0; + int i, j; if( zPath[0]!='/' ){ if( osGetcwd(zOut, nOut-2)==0 ){ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); @@ -39871,6 +40030,41 @@ static int mkFullPathname( return SQLITE_CANTOPEN_BKPT; } sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); + + /* Remove duplicate '/' characters. Except, two // at the beginning + ** of a pathname is allowed since this is important on windows. */ + for(i=j=1; zOut[i]; i++){ + zOut[j++] = zOut[i]; + while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; + } + zOut[j] = 0; + + assert( zOut[0]=='/' ); + for(i=j=0; zOut[i]; i++){ + if( zOut[i]=='/' ){ + /* Skip over internal "/." directory components */ + if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ + i += 1; + continue; + } + + /* If this is a "/.." directory component then back out the + ** previous term of the directory if it is something other than "..". + */ + if( zOut[i+1]=='.' + && zOut[i+2]=='.' + && zOut[i+3]=='/' + && unixBackupDir(zOut, &j) + ){ + i += 2; + continue; + } + } + if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; + j++; + } + if( NEVER(j==0) ) zOut[j++] = '/'; + zOut[j] = 0; return SQLITE_OK; } @@ -40091,7 +40285,8 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ UNUSED_PARAMETER(NotUsed); return microseconds; #elif defined(HAVE_USLEEP) && HAVE_USLEEP - usleep(microseconds); + if( microseconds>=1000000 ) sleep(microseconds/1000000); + if( microseconds%1000000 ) usleep(microseconds%1000000); UNUSED_PARAMETER(NotUsed); return microseconds; #else @@ -40664,7 +40859,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ if( nTries==1 ){ conchModTime = buf.st_mtimespec; - usleep(500000); /* wait 0.5 sec and try the lock again*/ + unixSleep(0,500000); /* wait 0.5 sec and try the lock again*/ continue; } @@ -40690,7 +40885,7 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ /* don't break the lock on short read or a version mismatch */ return SQLITE_BUSY; } - usleep(10000000); /* wait 10 sec and try the lock again */ + unixSleep(0,10000000); /* wait 10 sec and try the lock again */ continue; } @@ -46811,7 +47006,11 @@ static int winOpen( dwCreationDisposition = OPEN_EXISTING; } - dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + if( 0==sqlite3_uri_boolean(zName, "exclusive", 0) ){ + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; + }else{ + dwShareMode = 0; + } if( isDelete ){ #if SQLITE_OS_WINCE @@ -47964,11 +48163,14 @@ static const sqlite3_io_methods memdb_io_methods = { ** Close an memdb-file. ** ** The pData pointer is owned by the application, so there is nothing -** to free. +** to free. Unless the SQLITE_DESERIALIZE_FREEONCLOSE flag is set, +** in which case we own the pData pointer and need to free it. */ static int memdbClose(sqlite3_file *pFile){ MemFile *p = (MemFile *)pFile; - if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ) sqlite3_free(p->aData); + if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){ + sqlite3_free(p->aData); + } return SQLITE_OK; } @@ -48411,8 +48613,12 @@ SQLITE_API int sqlite3_deserialize( goto end_deserialize; } zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema); - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + } if( rc ) goto end_deserialize; db->init.iDb = (u8)iDb; db->init.reopenMemdb = 1; @@ -48427,6 +48633,7 @@ SQLITE_API int sqlite3_deserialize( rc = SQLITE_ERROR; }else{ p->aData = pData; + pData = 0; p->sz = szDb; p->szAlloc = szBuf; p->szMax = szBuf; @@ -48439,6 +48646,9 @@ SQLITE_API int sqlite3_deserialize( end_deserialize: sqlite3_finalize(pStmt); + if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){ + sqlite3_free(pData); + } sqlite3_mutex_leave(db->mutex); return rc; } @@ -54194,6 +54404,7 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ i64 nSuperJournal; /* Size of super-journal file */ char *zJournal; /* Pointer to one journal within MJ file */ char *zSuperPtr; /* Space to hold super-journal filename */ + char *zFree = 0; /* Free this buffer */ int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */ /* Allocate space for both the pJournal and pSuper file descriptors. @@ -54218,11 +54429,13 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ rc = sqlite3OsFileSize(pSuper, &nSuperJournal); if( rc!=SQLITE_OK ) goto delsuper_out; nSuperPtr = pVfs->mxPathname+1; - zSuperJournal = sqlite3Malloc(nSuperJournal + nSuperPtr + 2); - if( !zSuperJournal ){ + zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2); + if( !zFree ){ rc = SQLITE_NOMEM_BKPT; goto delsuper_out; } + zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0; + zSuperJournal = &zFree[4]; zSuperPtr = &zSuperJournal[nSuperJournal+2]; rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0); if( rc!=SQLITE_OK ) goto delsuper_out; @@ -54270,7 +54483,7 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ rc = sqlite3OsDelete(pVfs, zSuper, 0); delsuper_out: - sqlite3_free(zSuperJournal); + sqlite3_free(zFree); if( pSuper ){ sqlite3OsClose(pSuper); assert( !isOpen(pJournal) ); @@ -54608,7 +54821,11 @@ static int pager_playback(Pager *pPager, int isHot){ pPager->changeCountDone = pPager->tempFile; if( rc==SQLITE_OK ){ - zSuper = pPager->pTmpSpace; + /* Leave 4 bytes of space before the super-journal filename in memory. + ** This is because it may end up being passed to sqlite3OsOpen(), in + ** which case it requires 4 0x00 bytes in memory immediately before + ** the filename. */ + zSuper = &pPager->pTmpSpace[4]; rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1); testcase( rc!=SQLITE_OK ); } @@ -54625,6 +54842,8 @@ static int pager_playback(Pager *pPager, int isHot){ /* If there was a super-journal and this routine will return success, ** see if it is possible to delete the super-journal. */ + assert( zSuper==&pPager->pTmpSpace[4] ); + memset(&zSuper[-4], 0, 4); rc = pager_delsuper(pPager, zSuper); testcase( rc!=SQLITE_OK ); } @@ -63828,6 +64047,9 @@ struct Btree { u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */ Btree *pNext; /* List of other sharable Btrees from the same db */ Btree *pPrev; /* Back pointer of the same list */ +#ifdef SQLITE_DEBUG + u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */ +#endif #ifndef SQLITE_OMIT_SHARED_CACHE BtLock lock; /* Object used to lock page 1 */ #endif @@ -63839,11 +64061,25 @@ struct Btree { ** If the shared-data extension is enabled, there may be multiple users ** of the Btree structure. At most one of these may open a write transaction, ** but any number may have active read transactions. +** +** These values must match SQLITE_TXN_NONE, SQLITE_TXN_READ, and +** SQLITE_TXN_WRITE */ #define TRANS_NONE 0 #define TRANS_READ 1 #define TRANS_WRITE 2 +#if TRANS_NONE!=SQLITE_TXN_NONE +# error wrong numeric code for no-transaction +#endif +#if TRANS_READ!=SQLITE_TXN_READ +# error wrong numeric code for read-transaction +#endif +#if TRANS_WRITE!=SQLITE_TXN_WRITE +# error wrong numeric code for write-transaction +#endif + + /* ** An instance of this object represents a single database file. ** @@ -64595,6 +64831,17 @@ SQLITE_API int sqlite3_enable_shared_cache(int enable){ #define hasReadConflicts(a, b) 0 #endif +#ifdef SQLITE_DEBUG +/* +** Return and reset the seek counter for a Btree object. +*/ +SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ + u64 n = pBt->nSeek; + pBt->nSeek = 0; + return n; +} +#endif + /* ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single ** (MemPage*) as an argument. The (MemPage*) must not be NULL. @@ -67088,7 +67335,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen( ** do not change the pager-cache size. */ if( sqlite3BtreeSchema(p, 0, 0)==0 ){ - sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE); + sqlite3BtreeSetCacheSize(p, SQLITE_DEFAULT_CACHE_SIZE); } pFile = sqlite3PagerFile(pBt->pPager); @@ -69942,6 +70189,10 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( } } +#ifdef SQLITE_DEBUG + pCur->pBtree->nSeek++; /* Performance measurement during testing */ +#endif + if( pIdxKey ){ xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); pIdxKey->errCode = 0; @@ -70218,7 +70469,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){ pPage = pCur->pPage; idx = ++pCur->ix; - if( !pPage->isInit ){ + if( !pPage->isInit || sqlite3FaultSim(412) ){ /* The only known way for this to happen is for there to be a ** recursive SQL function that does a DELETE operation as part of a ** SELECT which deletes content out from under an active cursor @@ -74793,11 +75044,12 @@ SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *p){ } /* -** Return non-zero if a transaction is active. +** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE +** to describe the current transaction state of Btree p. */ -SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree *p){ +SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree *p){ assert( p==0 || sqlite3_mutex_held(p->db->mutex) ); - return (p && (p->inTrans==TRANS_WRITE)); + return p ? p->inTrans : 0; } #ifndef SQLITE_OMIT_WAL @@ -74826,14 +75078,8 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int * #endif /* -** Return non-zero if a read (or write) transaction is active. +** Return true if there is currently a backup running on Btree p. */ -SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree *p){ - assert( p ); - assert( sqlite3_mutex_held(p->db->mutex) ); - return p->inTrans!=TRANS_NONE; -} - SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){ assert( p ); assert( sqlite3_mutex_held(p->db->mutex) ); @@ -75179,7 +75425,7 @@ static int setDestPgsz(sqlite3_backup *p){ ** message in database handle db. */ static int checkReadTransaction(sqlite3 *db, Btree *p){ - if( sqlite3BtreeIsInReadTrans(p) ){ + if( sqlite3BtreeTxnState(p)!=SQLITE_TXN_NONE ){ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use"); return SQLITE_ERROR; } @@ -75410,7 +75656,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** one now. If a transaction is opened here, then it will be closed ** before this function exits. */ - if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){ + if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){ rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0); bCloseTrans = 1; } @@ -75782,7 +76028,7 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); - assert( sqlite3BtreeIsInTrans(pTo) ); + assert( sqlite3BtreeTxnState(pTo)==SQLITE_TXN_WRITE ); pFd = sqlite3PagerFile(sqlite3BtreePager(pTo)); if( pFd->pMethods ){ i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom); @@ -75818,7 +76064,7 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); } - assert( sqlite3BtreeIsInTrans(pTo)==0 ); + assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE ); copy_finished: sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); @@ -78213,6 +78459,7 @@ SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){ int j; sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); for(j=0; jdb->nDb; j++) sqlite3VdbeUsesBtree(p, j); + sqlite3MayAbort(p->pParse); } /* @@ -78441,7 +78688,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename || opcode==OP_VDestroy || opcode==OP_VCreate - || (opcode==OP_ParseSchema && pOp->p4.z==0) + || opcode==OP_ParseSchema || ((opcode==OP_Halt || opcode==OP_HaltIfNull) && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort)) ){ @@ -79259,7 +79506,7 @@ SQLITE_PRIVATE char *sqlite3VdbeDisplayComment( sqlite3_str_appendf(&x, "%d", v1); }else if( pCtx->argc>1 ){ sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1); - }else{ + }else if( x.accError==0 ){ assert( x.nChar>2 ); x.nChar -= 2; ii++; @@ -80401,7 +80648,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ */ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( sqlite3BtreeIsInTrans(pBt) ){ + if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ /* Whether or not a database might need a super-journal depends upon ** its journal mode (among other things). This matrix determines which ** journal modes use a super-journal and which do not */ @@ -80536,7 +80783,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ */ for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( sqlite3BtreeIsInTrans(pBt) ){ + if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ char const *zFile = sqlite3BtreeGetJournalname(pBt); if( zFile==0 ){ continue; /* Ignore TEMP and :memory: databases */ @@ -82032,9 +82279,12 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem static int sqlite3IntFloatCompare(i64 i, double r){ if( sizeof(LONGDOUBLE_TYPE)>8 ){ LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i; + testcase( xr ); + testcase( x==r ); if( xr ) return +1; - return 0; + if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */ + return 0; /*NO_TEST*/ /* work around bugs in gcov */ }else{ i64 y; double s; @@ -88814,7 +89064,8 @@ case OP_AutoCommit: { ** active. ** If P2 is non-zero, then a write-transaction is started, or if a ** read-transaction is already active, it is upgraded to a write-transaction. -** If P2 is zero, then a read-transaction is started. +** If P2 is zero, then a read-transaction is started. If P2 is 2 or more +** then an exclusive transaction is started. ** ** P1 is the index of the database file on which the transaction is ** started. Index 0 is the main database file and index 1 is the @@ -88848,6 +89099,7 @@ case OP_Transaction: { assert( p->bIsReader ); assert( p->readOnly==0 || pOp->p2==0 ); + assert( pOp->p2>=0 && pOp->p2<=2 ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( DbMaskTest(p->btreeMask, pOp->p1) ); if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){ @@ -88873,7 +89125,7 @@ case OP_Transaction: { && pOp->p2 && (db->autoCommit==0 || db->nVdbeRead>1) ){ - assert( sqlite3BtreeIsInTrans(pBt) ); + assert( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; @@ -89226,7 +89478,7 @@ case OP_OpenDup: { } -/* Opcode: OpenEphemeral P1 P2 * P4 P5 +/* Opcode: OpenEphemeral P1 P2 P3 P4 P5 ** Synopsis: nColumn=P2 ** ** Open a new cursor P1 to a transient table. @@ -89246,6 +89498,10 @@ case OP_OpenDup: { ** in btree.h. These flags control aspects of the operation of ** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are ** added automatically. +** +** If P3 is positive, then reg[P3] is modified slightly so that it +** can be used as zero-length data for OP_Insert. This is an optimization +** that avoids an extra OP_Blob opcode to initialize that register. */ /* Opcode: OpenAutoindex P1 P2 * P4 * ** Synopsis: nColumn=P2 @@ -89268,6 +89524,15 @@ case OP_OpenEphemeral: { SQLITE_OPEN_TRANSIENT_DB; assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); + if( pOp->p3>0 ){ + /* Make register reg[P3] into a value that can be used as the data + ** form sqlite3BtreeInsert() where the length of the data is zero. */ + assert( pOp->p2==0 ); /* Only used when number of columns is zero */ + assert( pOp->opcode==OP_OpenEphemeral ); + assert( aMem[pOp->p3].flags & MEM_Null ); + aMem[pOp->p3].n = 0; + aMem[pOp->p3].z = ""; + } pCx = p->apCsr[pOp->p1]; if( pCx && pCx->pBtx ){ /* If the ephermeral table is already open, erase all existing content @@ -89710,22 +89975,172 @@ case OP_SeekGT: { /* jump, in3, group */ break; } -/* Opcode: SeekHit P1 P2 * * * -** Synopsis: seekHit=P2 + +/* Opcode: SeekScan P1 P2 * * * +** Synopsis: Scan-ahead up to P1 rows +** +** This opcode is a prefix opcode to OP_SeekGE. In other words, this +** opcode must be immediately followed by OP_SeekGE. This constraint is +** checked by assert() statements. +** +** This opcode uses the P1 through P4 operands of the subsequent +** OP_SeekGE. In the text that follows, the operands of the subsequent +** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only +** the P1 and P2 operands of this opcode are also used, and are called +** This.P1 and This.P2. +** +** This opcode helps to optimize IN operators on a multi-column index +** where the IN operator is on the later terms of the index by avoiding +** unnecessary seeks on the btree, substituting steps to the next row +** of the b-tree instead. A correct answer is obtained if this opcode +** is omitted or is a no-op. +** +** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which +** is the desired entry that we want the cursor SeekGE.P1 to be pointing +** to. Call this SeekGE.P4/P5 row the "target". +** +** If the SeekGE.P1 cursor is not currently pointing to a valid row, +** then this opcode is a no-op and control passes through into the OP_SeekGE. +** +** If the SeekGE.P1 cursor is pointing to a valid row, then that row +** might be the target row, or it might be near and slightly before the +** target row. This opcode attempts to position the cursor on the target +** row by, perhaps by invoking sqlite3BtreeStep() on the cursor +** between 0 and This.P1 times. +** +** There are three possible outcomes from this opcode:
    +** +**
  1. If after This.P1 steps, the cursor is still point to a place that +** is earlier in the btree than the target row, +** then fall through into the subsquence OP_SeekGE opcode. +** +**
  2. If the cursor is successfully moved to the target row by 0 or more +** sqlite3BtreeNext() calls, then jump to This.P2, which will land just +** past the OP_IdxGT opcode that follows the OP_SeekGE. +** +**
  3. If the cursor ends up past the target row (indicating the the target +** row does not exist in the btree) then jump to SeekOP.P2. +**
+*/ +case OP_SeekScan: { + VdbeCursor *pC; + int res; + int nStep; + UnpackedRecord r; + + assert( pOp[1].opcode==OP_SeekGE ); + + /* pOp->p2 points to the first instruction past the OP_IdxGT that + ** follows the OP_SeekGE. */ + assert( pOp->p2>=(int)(pOp-aOp)+2 ); + assert( aOp[pOp->p2-1].opcode==OP_IdxGT ); + assert( pOp[1].p1==aOp[pOp->p2-1].p1 ); + assert( pOp[1].p2==aOp[pOp->p2-1].p2 ); + assert( pOp[1].p3==aOp[pOp->p2-1].p3 ); + + assert( pOp->p1>0 ); + pC = p->apCsr[pOp[1].p1]; + assert( pC!=0 ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( !pC->isTable ); + if( !sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("... cursor not valid - fall through\n"); + } +#endif + break; + } + nStep = pOp->p1; + assert( nStep>=1 ); + r.pKeyInfo = pC->pKeyInfo; + r.nField = (u16)pOp[1].p4.i; + r.default_rc = 0; + r.aMem = &aMem[pOp[1].p3]; +#ifdef SQLITE_DEBUG + { + int i; + for(i=0; i0 ){ + seekscan_search_fail: +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("... %d steps and then skip\n", pOp->p1 - nStep); + } +#endif + VdbeBranchTaken(1,3); + pOp++; + goto jump_to_p2; + } + if( res==0 ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("... %d steps and then success\n", pOp->p1 - nStep); + } +#endif + VdbeBranchTaken(2,3); + goto jump_to_p2; + break; + } + if( nStep<=0 ){ +#ifdef SQLITE_DEBUG + if( db->flags&SQLITE_VdbeTrace ){ + printf("... fall through after %d steps\n", pOp->p1); + } +#endif + VdbeBranchTaken(0,3); + break; + } + nStep--; + rc = sqlite3BtreeNext(pC->uc.pCursor, 0); + if( rc ){ + if( rc==SQLITE_DONE ){ + rc = SQLITE_OK; + goto seekscan_search_fail; + }else{ + goto abort_due_to_error; + } + } + } + + break; +} + + +/* Opcode: SeekHit P1 P2 P3 * * +** Synopsis: set P2<=seekHit<=P3 +** +** Increase or decrease the seekHit value for cursor P1, if necessary, +** so that it is no less than P2 and no greater than P3. ** -** Set the seekHit flag on cursor P1 to the value in P2. -** The seekHit flag is used by the IfNoHope opcode. +** The seekHit integer represents the maximum of terms in an index for which +** there is known to be at least one match. If the seekHit value is smaller +** than the total number of equality terms in an index lookup, then the +** OP_IfNoHope opcode might run to see if the IN loop can be abandoned +** early, thus saving work. This is part of the IN-early-out optimization. ** -** P1 must be a valid b-tree cursor. P2 must be a boolean value, -** either 0 or 1. +** P1 must be a valid b-tree cursor. */ case OP_SeekHit: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); - assert( pOp->p2==0 || pOp->p2==1 ); - pC->seekHit = pOp->p2 & 1; + assert( pOp->p3>=pOp->p2 ); + if( pC->seekHitp2 ){ + pC->seekHit = pOp->p2; + }else if( pC->seekHit>pOp->p3 ){ + pC->seekHit = pOp->p3; + } break; } @@ -89783,16 +90198,20 @@ case OP_IfNotOpen: { /* jump */ ** Synopsis: key=r[P3@P4] ** ** Register P3 is the first of P4 registers that form an unpacked -** record. +** record. Cursor P1 is an index btree. P2 is a jump destination. +** In other words, the operands to this opcode are the same as the +** operands to OP_NotFound and OP_IdxGT. ** -** Cursor P1 is on an index btree. If the seekHit flag is set on P1, then -** this opcode is a no-op. But if the seekHit flag of P1 is clear, then -** check to see if there is any entry in P1 that matches the -** prefix identified by P3 and P4. If no entry matches the prefix, -** jump to P2. Otherwise fall through. +** This opcode is an optimization attempt only. If this opcode always +** falls through, the correct answer is still obtained, but extra works +** is performed. ** -** This opcode behaves like OP_NotFound if the seekHit -** flag is clear and it behaves like OP_Noop if the seekHit flag is set. +** A value of N in the seekHit flag of cursor P1 means that there exists +** a key P3:N that will match some record in the index. We want to know +** if it is possible for a record P3:P4 to match some record in the +** index. If it is not possible, we can skips some work. So if seekHit +** is less than P4, attempt to find out if a match is possible by running +** OP_NotFound. ** ** This opcode is used in IN clause processing for a multi-column key. ** If an IN clause is attached to an element of the key other than the @@ -89834,7 +90253,7 @@ case OP_IfNoHope: { /* jump, in3 */ assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); - if( pC->seekHit ) break; + if( pC->seekHit>=pOp->p4.i ) break; /* Fall through into OP_NotFound */ /* no break */ deliberate_fall_through } @@ -89916,6 +90335,7 @@ case OP_Found: { /* jump, in3 */ }else{ VdbeBranchTaken(takeJump||alreadyExists==0,2); if( takeJump || !alreadyExists ) goto jump_to_p2; + if( pOp->opcode==OP_IfNoHope ) pC->seekHit = pOp->p4.i; } break; } @@ -90272,7 +90692,7 @@ case OP_Insert: { if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey; - assert( pData->flags & (MEM_Blob|MEM_Str) ); + assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 ); x.pData = pData->z; x.nData = pData->n; seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); @@ -91148,7 +91568,7 @@ case OP_FinishSeek: { break; } -/* Opcode: IdxGE P1 P2 P3 P4 P5 +/* Opcode: IdxGE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index @@ -91159,7 +91579,7 @@ case OP_FinishSeek: { ** If the P1 index entry is greater than or equal to the key value ** then jump to P2. Otherwise fall through to the next instruction. */ -/* Opcode: IdxGT P1 P2 P3 P4 P5 +/* Opcode: IdxGT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index @@ -91170,7 +91590,7 @@ case OP_FinishSeek: { ** If the P1 index entry is greater than the key value ** then jump to P2. Otherwise fall through to the next instruction. */ -/* Opcode: IdxLT P1 P2 P3 P4 P5 +/* Opcode: IdxLT P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index @@ -91181,7 +91601,7 @@ case OP_FinishSeek: { ** If the P1 index entry is less than the key value then jump to P2. ** Otherwise fall through to the next instruction. */ -/* Opcode: IdxLE P1 P2 P3 P4 P5 +/* Opcode: IdxLE P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** ** The P4 register values beginning with P3 form an unpacked index @@ -91207,7 +91627,6 @@ case OP_IdxGE: { /* jump */ assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0); assert( pC->deferredMoveto==0 ); - assert( pOp->p5==0 || pOp->p5==1 ); assert( pOp->p4type==P4_INT32 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; @@ -91228,8 +91647,31 @@ case OP_IdxGE: { /* jump */ } } #endif - res = 0; /* Not needed. Only used to silence a warning. */ - rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res); + + /* Inlined version of sqlite3VdbeIdxKeyCompare() */ + { + i64 nCellKey = 0; + BtCursor *pCur; + Mem m; + + assert( pC->eCurType==CURTYPE_BTREE ); + pCur = pC->uc.pCursor; + assert( sqlite3BtreeCursorIsValid(pCur) ); + nCellKey = sqlite3BtreePayloadSize(pCur); + /* nCellKey will always be between 0 and 0xffffffff because of the way + ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ + if( nCellKey<=0 || nCellKey>0x7fffffff ){ + rc = SQLITE_CORRUPT_BKPT; + goto abort_due_to_error; + } + sqlite3VdbeMemInit(&m, db, 0); + rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m); + if( rc ) goto abort_due_to_error; + res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, &r, 0); + sqlite3VdbeMemRelease(&m); + } + /* End of inlined sqlite3VdbeIdxKeyCompare() */ + assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) ); if( (pOp->opcode&1)==(OP_IdxLT&1) ){ assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT ); @@ -91239,7 +91681,7 @@ case OP_IdxGE: { /* jump */ res++; } VdbeBranchTaken(res>0,2); - if( rc ) goto abort_due_to_error; + assert( rc==SQLITE_OK ); if( res>0 ) goto jump_to_p2; break; } @@ -92365,7 +92807,7 @@ case OP_JournalMode: { /* out2 */ /* Open a transaction on the database file. Regardless of the journal ** mode, this transaction always uses a rollback journal. */ - assert( sqlite3BtreeIsInTrans(pBt)==0 ); + assert( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ); if( rc==SQLITE_OK ){ rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); } @@ -93305,7 +93747,11 @@ default: { /* This is really OP_Noop, OP_Explain */ ** an error of some kind. */ abort_due_to_error: - if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT; + if( db->mallocFailed ){ + rc = SQLITE_NOMEM_BKPT; + }else if( rc==SQLITE_IOERR_CORRUPTFS ){ + rc = SQLITE_CORRUPT_BKPT; + } assert( rc ); if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){ sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); @@ -94854,13 +95300,16 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit( if( pSorter==0 ){ rc = SQLITE_NOMEM_BKPT; }else{ + Btree *pBt = db->aDb[0].pBt; pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz); memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo); pKeyInfo->db = 0; if( nField && nWorker==0 ){ pKeyInfo->nKeyField = nField; } - pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt); + sqlite3BtreeEnter(pBt); + pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(pBt); + sqlite3BtreeLeave(pBt); pSorter->nTask = nWorker + 1; pSorter->iPrev = (u8)(nWorker - 1); pSorter->bUseThreads = (pSorter->nTask>1); @@ -98830,7 +99279,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ assert( !ExprHasProperty(pExpr, EP_Reduced) ); /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE", ** and "x IS NOT FALSE". */ - if( pRight && pRight->op==TK_ID ){ + if( pRight && (pRight->op==TK_ID || pRight->op==TK_TRUEFALSE) ){ int rc = resolveExprStep(pWalker, pRight); if( rc==WRC_Abort ) return WRC_Abort; if( pRight->op==TK_TRUEFALSE ){ @@ -99039,6 +99488,7 @@ static int resolveCompoundOrderBy( Expr *pE, *pDup; if( pItem->done ) continue; pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr); + if( NEVER(pE==0) ) continue; if( sqlite3ExprIsInteger(pE, &iCol) ){ if( iCol<=0 || iCol>pEList->nExpr ){ resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr); @@ -99218,6 +99668,7 @@ static int resolveOrderGroupBy( for(i=0, pItem=pOrderBy->a; inExpr; i++, pItem++){ Expr *pE = pItem->pExpr; Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE); + if( NEVER(pE2==0) ) continue; if( zType[0]!='G' ){ iCol = resolveAsName(pParse, pSelect->pEList, pE2); if( iCol>0 ){ @@ -99758,8 +100209,10 @@ SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){ */ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){ int op; - while( ExprHasProperty(pExpr, EP_Skip) ){ - assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW ); + while( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){ + assert( pExpr->op==TK_COLLATE + || pExpr->op==TK_IF_NULL_ROW + || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) ); pExpr = pExpr->pLeft; assert( pExpr!=0 ); } @@ -99829,7 +100282,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, con */ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ - assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW ); + assert( pExpr->op==TK_COLLATE ); pExpr = pExpr->pLeft; } return pExpr; @@ -99848,7 +100301,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){ assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; }else{ - assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW ); + assert( pExpr->op==TK_COLLATE ); pExpr = pExpr->pLeft; } } @@ -100482,6 +100935,7 @@ SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){ ** Expr.flags. */ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){ + if( pParse->nErr ) return; if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } @@ -103334,6 +103788,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n */ static void exprToRegister(Expr *pExpr, int iReg){ Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr); + if( NEVER(p==0) ) return; p->op2 = p->op; p->op = TK_REGISTER; p->iTable = iReg; @@ -104321,6 +104776,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ int r2; pExpr = sqlite3ExprSkipCollateAndLikely(pExpr); if( ConstFactorOk(pParse) + && ALWAYS(pExpr!=0) && pExpr->op!=TK_REGISTER && sqlite3ExprIsConstantNotJoin(pExpr) ){ @@ -106995,13 +107451,21 @@ static int renameResolveTrigger(Parse *pParse){ int i; for(i=0; inSrc && rc==SQLITE_OK; i++){ struct SrcList_item *p = &pSrc->a[i]; - p->pTab = sqlite3LocateTableItem(pParse, 0, p); p->iCursor = pParse->nTab++; - if( p->pTab==0 ){ - rc = SQLITE_ERROR; + if( p->pSelect ){ + sqlite3SelectPrep(pParse, p->pSelect, 0); + sqlite3ExpandSubquery(pParse, p); + assert( i>0 ); + assert( pStep->pFrom->a[i-1].pSelect ); + sqlite3SelectPrep(pParse, pStep->pFrom->a[i-1].pSelect, 0); }else{ - p->pTab->nTabRef++; - rc = sqlite3ViewGetColumnNames(pParse, p->pTab); + p->pTab = sqlite3LocateTableItem(pParse, 0, p); + if( p->pTab==0 ){ + rc = SQLITE_ERROR; + }else{ + p->pTab->nTabRef++; + rc = sqlite3ViewGetColumnNames(pParse, p->pTab); + } } } sNC.pSrcList = pSrc; @@ -107063,6 +107527,12 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); } + if( pStep->pFrom ){ + int i; + for(i=0; ipFrom->nSrc; i++){ + sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect); + } + } } } @@ -109321,6 +109791,7 @@ static int loadStatTbl( } pSpace = (tRowcnt*)&pIdx->aSample[nSample]; pIdx->aAvgEq = pSpace; pSpace += nIdxCol; + pIdx->pTable->tabFlags |= TF_HasStat4; for(i=0; iaSample[i].anEq = pSpace; pSpace += nIdxCol; pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol; @@ -109787,7 +110258,9 @@ static void detachFunc( sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); goto detach_error; } - if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){ + if( sqlite3BtreeTxnState(pDb->pBt)!=SQLITE_TXN_NONE + || sqlite3BtreeIsInBackup(pDb->pBt) + ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; } @@ -110447,7 +110920,7 @@ SQLITE_PRIVATE void sqlite3TableLock( u8 isWriteLock, /* True for a write lock */ const char *zName /* Name of the table to be locked */ ){ - Parse *pToplevel = sqlite3ParseToplevel(pParse); + Parse *pToplevel; int i; int nBytes; TableLock *p; @@ -110455,6 +110928,7 @@ SQLITE_PRIVATE void sqlite3TableLock( if( iDb==1 ) return; if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; + pToplevel = sqlite3ParseToplevel(pParse); for(i=0; inTableLock; i++){ p = &pToplevel->aTableLock[i]; if( p->iDb==iDb && p->iTab==iTab ){ @@ -110484,10 +110958,8 @@ SQLITE_PRIVATE void sqlite3TableLock( */ static void codeTableLocks(Parse *pParse){ int i; - Vdbe *pVdbe; - - pVdbe = sqlite3GetVdbe(pParse); - assert( pVdbe!=0 ); /* sqlite3GetVdbe cannot fail: VDBE already allocated */ + Vdbe *pVdbe = pParse->pVdbe; + assert( pVdbe!=0 ); for(i=0; inTableLock; i++){ TableLock *p = &pParse->aTableLock[i]; @@ -112012,8 +112484,10 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( ** Add a new CHECK constraint to the table currently under construction. */ SQLITE_PRIVATE void sqlite3AddCheckConstraint( - Parse *pParse, /* Parsing context */ - Expr *pCheckExpr /* The check expression */ + Parse *pParse, /* Parsing context */ + Expr *pCheckExpr, /* The check expression */ + const char *zStart, /* Opening "(" */ + const char *zEnd /* Closing ")" */ ){ #ifndef SQLITE_OMIT_CHECK Table *pTab = pParse->pNewTable; @@ -112024,6 +112498,13 @@ SQLITE_PRIVATE void sqlite3AddCheckConstraint( pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr); if( pParse->constraintName.n ){ sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1); + }else{ + Token t; + for(zStart++; sqlite3Isspace(zStart[0]); zStart++){} + while( sqlite3Isspace(zEnd[-1]) ){ zEnd--; } + t.z = zStart; + t.n = (int)(zEnd - t.z); + sqlite3ExprListSetName(pParse, pTab->pCheck, &t, 1); } }else #endif @@ -112042,7 +112523,7 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){ char *zColl; /* Dequoted name of collation sequence */ sqlite3 *db; - if( (p = pParse->pNewTable)==0 ) return; + if( (p = pParse->pNewTable)==0 || IN_RENAME_OBJECT ) return; i = p->nCol-1; db = pParse->db; zColl = sqlite3NameFromToken(db, pToken); @@ -112277,12 +112758,15 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){ int nByte; if( pIdx->nColumn>=N ) return SQLITE_OK; assert( pIdx->isResized==0 ); - nByte = (sizeof(char*) + sizeof(i16) + 1)*N; + nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N; zExtra = sqlite3DbMallocZero(db, nByte); if( zExtra==0 ) return SQLITE_NOMEM_BKPT; memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn); pIdx->azColl = (const char**)zExtra; zExtra += sizeof(char*)*N; + memcpy(zExtra, pIdx->aiRowLogEst, sizeof(LogEst)*(pIdx->nKeyCol+1)); + pIdx->aiRowLogEst = (LogEst*)zExtra; + zExtra += sizeof(LogEst)*N; memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn); pIdx->aiColumn = (i16*)zExtra; zExtra += sizeof(i16)*N; @@ -114843,7 +115327,7 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ assert(pList || pParse->db->mallocFailed ); if( pList ){ for(i=0, pItem=pList->a; inSrc; i++, pItem++){ - if( pItem->iCursor>=0 ) break; + if( pItem->iCursor>=0 ) continue; pItem->iCursor = pParse->nTab++; if( pItem->pSelect ){ sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); @@ -114860,15 +115344,15 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ struct SrcList_item *pItem; if( pList==0 ) return; for(pItem=pList->a, i=0; inSrc; i++, pItem++){ - sqlite3DbFree(db, pItem->zDatabase); + if( pItem->zDatabase ) sqlite3DbFreeNN(db, pItem->zDatabase); sqlite3DbFree(db, pItem->zName); - sqlite3DbFree(db, pItem->zAlias); + if( pItem->zAlias ) sqlite3DbFreeNN(db, pItem->zAlias); if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); sqlite3DeleteTable(db, pItem->pTab); - sqlite3SelectDelete(db, pItem->pSelect); - sqlite3ExprDelete(db, pItem->pOn); - sqlite3IdListDelete(db, pItem->pUsing); + if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect); + if( pItem->pOn ) sqlite3ExprDelete(db, pItem->pOn); + if( pItem->pUsing ) sqlite3IdListDelete(db, pItem->pUsing); } sqlite3DbFreeNN(db, pList); } @@ -115040,7 +115524,16 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){ if( !v ) return; if( type!=TK_DEFERRED ){ for(i=0; inDb; i++){ - sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1); + int eTxnType; + Btree *pBt = db->aDb[i].pBt; + if( pBt && sqlite3BtreeIsReadonly(pBt) ){ + eTxnType = 0; /* Read txn */ + }else if( type==TK_EXCLUSIVE ){ + eTxnType = 2; /* Exclusive txn */ + }else{ + eTxnType = 1; /* Write txn */ + } + sqlite3VdbeAddOp2(v, OP_Transaction, i, eTxnType); sqlite3VdbeUsesBtree(v, i); } } @@ -115129,13 +115622,11 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){ ** will occur at the end of the top-level VDBE and will be generated ** later, by sqlite3FinishCoding(). */ -SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ - Parse *pToplevel = sqlite3ParseToplevel(pParse); - - assert( iDb>=0 && iDbdb->nDb ); - assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 ); +static void sqlite3CodeVerifySchemaAtToplevel(Parse *pToplevel, int iDb){ + assert( iDb>=0 && iDbdb->nDb ); + assert( pToplevel->db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDbdb, iDb, 0) ); + assert( sqlite3SchemaMutexHeld(pToplevel->db, iDb, 0) ); if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ DbMaskSet(pToplevel->cookieMask, iDb); if( !OMIT_TEMPDB && iDb==1 ){ @@ -115143,6 +115634,10 @@ SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ } } } +SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ + sqlite3CodeVerifySchemaAtToplevel(sqlite3ParseToplevel(pParse), iDb); +} + /* ** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each @@ -115174,7 +115669,7 @@ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb) */ SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); - sqlite3CodeVerifySchema(pParse, iDb); + sqlite3CodeVerifySchemaAtToplevel(pToplevel, iDb); DbMaskSet(pToplevel->writeMask, iDb); pToplevel->isMultiWrite |= setStatement; } @@ -115225,7 +115720,9 @@ SQLITE_PRIVATE void sqlite3HaltConstraint( i8 p4type, /* P4_STATIC or P4_TRANSIENT */ u8 p5Errmsg /* P5_ErrMsg type */ ){ - Vdbe *v = sqlite3GetVdbe(pParse); + Vdbe *v; + assert( pParse->pVdbe!=0 ); + v = sqlite3GetVdbe(pParse); assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested ); if( onError==OE_Abort ){ sqlite3MayAbort(pParse); @@ -116506,7 +117003,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( }else #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */ { - u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE; + u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK; if( sNC.ncFlags & NC_VarSelect ) bComplex = 1; wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); if( HasRowid(pTab) ){ @@ -116542,6 +117039,9 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF ); if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse); + if( sqlite3WhereUsesDeferredSeek(pWInfo) ){ + sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur); + } /* Keep track of the number of rows to be deleted */ if( memCnt ){ @@ -116576,6 +117076,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0; if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0; if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen); + addrBypass = sqlite3VdbeMakeLabel(pParse); }else{ if( pPk ){ /* Add the PK key for this row to the temporary table */ @@ -116589,13 +117090,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom( nKey = 1; /* OP_DeferredSeek always uses a single rowid */ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); } - } - - /* If this DELETE cannot use the ONEPASS strategy, this is the - ** end of the WHERE loop */ - if( eOnePass!=ONEPASS_OFF ){ - addrBypass = sqlite3VdbeMakeLabel(pParse); - }else{ sqlite3WhereEnd(pWInfo); } @@ -117026,10 +117520,6 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey( } if( regOut ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); - if( pIdx->pTable->pSelect ){ - const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx); - sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT); - } } sqlite3ReleaseTempRange(pParse, regBase, nCol); return regBase; @@ -119045,6 +119535,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), + FUNCTION(substring, 2, 0, 0, substrFunc ), + FUNCTION(substring, 3, 0, 0, substrFunc ), WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0), WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0), WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0), @@ -120585,7 +121077,8 @@ SQLITE_PRIVATE void sqlite3OpenTable( ){ Vdbe *v; assert( !IsVirtual(pTab) ); - v = sqlite3GetVdbe(pParse); + assert( pParse->pVdbe!=0 ); + v = pParse->pVdbe; assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); sqlite3TableLock(pParse, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); @@ -122084,7 +122577,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( isUpdate = regOldData!=0; db = pParse->db; - v = sqlite3GetVdbe(pParse); + v = pParse->pVdbe; assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; @@ -122238,7 +122731,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( sqlite3VdbeGoto(v, ignoreDest); }else{ char *zName = pCheck->a[i].zEName; - if( zName==0 ) zName = pTab->zName; + assert( zName!=0 || pParse->db->mallocFailed ); if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, onError, zName, P4_TRANSIENT, @@ -122857,7 +123350,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION) ); - v = sqlite3GetVdbe(pParse); + v = pParse->pVdbe; assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ @@ -122958,7 +123451,7 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices( return 0; } iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - v = sqlite3GetVdbe(pParse); + v = pParse->pVdbe; assert( v!=0 ); if( iBase<0 ) iBase = pParse->nTab; iDataCur = iBase++; @@ -123930,6 +124423,8 @@ struct sqlite3_api_routines { int,const char**); void (*free_filename)(char*); sqlite3_file *(*database_file_object)(const char*); + /* Version 3.34.0 and later */ + int (*txn_state)(sqlite3*,const char*); }; /* @@ -124234,6 +124729,8 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_create_filename sqlite3_api->create_filename #define sqlite3_free_filename sqlite3_api->free_filename #define sqlite3_database_file_object sqlite3_api->database_file_object +/* Version 3.34.0 and later */ +#define sqlite3_txn_state sqlite3_api->txn_state #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -124716,6 +125213,8 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_create_filename, sqlite3_free_filename, sqlite3_database_file_object, + /* Version 3.34.0 and later */ + sqlite3_txn_state, }; /* True if x is the directory separator character @@ -125876,7 +126375,9 @@ static int getTempStore(const char *z){ static int invalidateTempStorage(Parse *pParse){ sqlite3 *db = pParse->db; if( db->aDb[1].pBt!=0 ){ - if( !db->autoCommit || sqlite3BtreeIsInReadTrans(db->aDb[1].pBt) ){ + if( !db->autoCommit + || sqlite3BtreeTxnState(db->aDb[1].pBt)!=SQLITE_TXN_NONE + ){ sqlite3ErrorMsg(pParse, "temporary storage cannot be changed " "from within a transaction"); return SQLITE_ERROR; @@ -127196,7 +127697,7 @@ SQLITE_PRIVATE void sqlite3Pragma( aiCols = 0; if( pParent ){ x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols); - assert( x==0 ); + assert( x==0 || db->mallocFailed ); } addrOk = sqlite3VdbeMakeLabel(pParse); @@ -127221,7 +127722,7 @@ SQLITE_PRIVATE void sqlite3Pragma( int jmp = sqlite3VdbeCurrentAddr(v)+2; sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v); sqlite3VdbeGoto(v, addrOk); - assert( pFK->nCol==1 ); + assert( pFK->nCol==1 || db->mallocFailed ); } /* Generate code to report an FK violation to the caller. */ @@ -128579,7 +129080,7 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed before this function returns. */ sqlite3BtreeEnter(pDb->pBt); - if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){ + if( sqlite3BtreeTxnState(pDb->pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0); if( rc!=SQLITE_OK ){ sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc)); @@ -128822,7 +129323,7 @@ static void schemaIsValid(Parse *pParse){ /* If there is not already a read-only (or read-write) transaction opened ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed immediately after reading the meta-value. */ - if( !sqlite3BtreeIsInReadTrans(pBt) ){ + if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); @@ -129085,6 +129586,7 @@ static int sqlite3LockAndPrepare( sqlite3BtreeLeaveAll(db); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); + db->busyHandler.nBusy = 0; sqlite3_mutex_leave(db->mutex); return rc; } @@ -131271,6 +131773,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( char *zName; /* Column name */ int nName; /* Size of name in zName[] */ Hash ht; /* Hash table of column names */ + Table *pTab; sqlite3HashInit(&ht); if( pEList ){ @@ -131293,15 +131796,13 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList( /* If the column contains an "AS " phrase, use as the name */ }else{ Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr); - while( pColExpr->op==TK_DOT ){ + while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){ pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } - if( pColExpr->op==TK_COLUMN ){ + if( pColExpr->op==TK_COLUMN && (pTab = pColExpr->y.pTab)!=0 ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; - Table *pTab = pColExpr->y.pTab; - assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; }else if( pColExpr->op==TK_ID ){ @@ -131639,6 +132140,7 @@ static void generateWithRecursiveQuery( int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */ Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */ Select *pSetup = p->pPrior; /* The setup query */ + Select *pFirstRec; /* Left-most recursive term */ int addrTop; /* Top of the loop */ int addrCont, addrBreak; /* CONTINUE and BREAK addresses */ int iCurrent = 0; /* The Current table */ @@ -131714,7 +132216,25 @@ static void generateWithRecursiveQuery( /* Detach the ORDER BY clause from the compound SELECT */ p->pOrderBy = 0; + /* Figure out how many elements of the compound SELECT are part of the + ** recursive query. Make sure no recursive elements use aggregate + ** functions. Mark the recursive elements as UNION ALL even if they + ** are really UNION because the distinctness will be enforced by the + ** iDistinct table. pFirstRec is left pointing to the left-most + ** recursive term of the CTE. + */ + pFirstRec = p; + for(pFirstRec=p; ALWAYS(pFirstRec!=0); pFirstRec=pFirstRec->pPrior){ + if( pFirstRec->selFlags & SF_Aggregate ){ + sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); + goto end_of_recursive_query; + } + pFirstRec->op = TK_ALL; + if( (pFirstRec->pPrior->selFlags & SF_Recursive)==0 ) break; + } + /* Store the results of the setup-query in Queue. */ + pSetup = pFirstRec->pPrior; pSetup->pNext = 0; ExplainQueryPlan((pParse, 1, "SETUP")); rc = sqlite3Select(pParse, pSetup, &destQueue); @@ -131747,15 +132267,11 @@ static void generateWithRecursiveQuery( /* Execute the recursive SELECT taking the single row in Current as ** the value for the recursive-table. Store the results in the Queue. */ - if( p->selFlags & SF_Aggregate ){ - sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); - }else{ - p->pPrior = 0; - ExplainQueryPlan((pParse, 1, "RECURSIVE STEP")); - sqlite3Select(pParse, p, &destQueue); - assert( p->pPrior==0 ); - p->pPrior = pSetup; - } + pFirstRec->pPrior = 0; + ExplainQueryPlan((pParse, 1, "RECURSIVE STEP")); + sqlite3Select(pParse, p, &destQueue); + assert( pFirstRec->pPrior==0 ); + pFirstRec->pPrior = pSetup; /* Keep running the loop until the Queue is empty */ sqlite3VdbeGoto(v, addrTop); @@ -131824,6 +132340,16 @@ static int multiSelectValues( return rc; } +/* +** Return true if the SELECT statement which is known to be the recursive +** part of a recursive CTE still has its anchor terms attached. If the +** anchor terms have already been removed, then return false. +*/ +static int hasAnchor(Select *p){ + while( p && (p->selFlags & SF_Recursive)!=0 ){ p = p->pPrior; } + return p!=0; +} + /* ** This routine is called to process a compound query form from ** two or more separate queries using UNION, UNION ALL, EXCEPT, or @@ -131909,7 +132435,7 @@ static int multiSelect( assert( p->pEList->nExpr==pPrior->pEList->nExpr ); #ifndef SQLITE_OMIT_CTE - if( p->selFlags & SF_Recursive ){ + if( (p->selFlags & SF_Recursive)!=0 && hasAnchor(p) ){ generateWithRecursiveQuery(pParse, p, &dest); }else #endif @@ -132001,6 +132527,7 @@ static int multiSelect( assert( p->pEList ); } + /* Code the SELECT statements to our left */ assert( !pPrior->pOrderBy ); @@ -132805,7 +133332,7 @@ static Expr *substExpr( ifNullRow.op = TK_IF_NULL_ROW; ifNullRow.pLeft = pCopy; ifNullRow.iTable = pSubst->iNewTable; - ifNullRow.flags = EP_Skip; + ifNullRow.flags = EP_IfNullRow; pCopy = &ifNullRow; } testcase( ExprHasProperty(pCopy, EP_Subquery) ); @@ -132814,8 +133341,7 @@ static Expr *substExpr( ExprSetProperty(pNew, EP_CanBeNull); } if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){ - pNew->iRightJoinTable = pExpr->iRightJoinTable; - ExprSetProperty(pNew, EP_FromJoin); + sqlite3SetJoinExpr(pNew, pExpr->iRightJoinTable); } sqlite3ExprDelete(db, pExpr); pExpr = pNew; @@ -134094,8 +134620,10 @@ static int withExpand( ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ + Select *pRecTerm; /* Left-most recursive term */ int bMayRecursive; /* True if compound joined by UNION [ALL] */ With *pSavedWith; /* Initial value of pParse->pWith */ + int iRecTab = -1; /* Cursor for recursive table */ /* If pCte->zCteErr is non-NULL at this point, then this is an illegal ** recursive reference to CTE pCte. Leave an error in pParse and return @@ -134120,44 +134648,48 @@ static int withExpand( assert( pFrom->pSelect ); /* Check if this is a recursive CTE. */ - pSel = pFrom->pSelect; + pRecTerm = pSel = pFrom->pSelect; bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); - if( bMayRecursive ){ + while( bMayRecursive && pRecTerm->op==pSel->op ){ int i; - SrcList *pSrc = pFrom->pSelect->pSrc; + SrcList *pSrc = pRecTerm->pSrc; + assert( pRecTerm->pPrior!=0 ); for(i=0; inSrc; i++){ struct SrcList_item *pItem = &pSrc->a[i]; if( pItem->zDatabase==0 && pItem->zName!=0 && 0==sqlite3StrICmp(pItem->zName, pCte->zName) - ){ + ){ pItem->pTab = pTab; - pItem->fg.isRecursive = 1; pTab->nTabRef++; - pSel->selFlags |= SF_Recursive; + pItem->fg.isRecursive = 1; + if( pRecTerm->selFlags & SF_Recursive ){ + sqlite3ErrorMsg(pParse, + "multiple references to recursive table: %s", pCte->zName + ); + return SQLITE_ERROR; + } + pRecTerm->selFlags |= SF_Recursive; + if( iRecTab<0 ) iRecTab = pParse->nTab++; + pItem->iCursor = iRecTab; } } + if( (pRecTerm->selFlags & SF_Recursive)==0 ) break; + pRecTerm = pRecTerm->pPrior; } - /* Only one recursive reference is permitted. */ - if( pTab->nTabRef>2 ){ - sqlite3ErrorMsg( - pParse, "multiple references to recursive table: %s", pCte->zName - ); - return SQLITE_ERROR; - } - assert( pTab->nTabRef==1 || - ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 )); - pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; pParse->pWith = pWith; - if( bMayRecursive ){ - Select *pPrior = pSel->pPrior; - assert( pPrior->pWith==0 ); - pPrior->pWith = pSel->pWith; - sqlite3WalkSelect(pWalker, pPrior); - pPrior->pWith = 0; + if( pSel->selFlags & SF_Recursive ){ + assert( pRecTerm!=0 ); + assert( (pRecTerm->selFlags & SF_Recursive)==0 ); + assert( pRecTerm->pNext!=0 ); + assert( (pRecTerm->pNext->selFlags & SF_Recursive)!=0 ); + assert( pRecTerm->pWith==0 ); + pRecTerm->pWith = pSel->pWith; + sqlite3WalkSelect(pWalker, pRecTerm); + pRecTerm->pWith = 0; }else{ sqlite3WalkSelect(pWalker, pSel); } @@ -135107,13 +135639,11 @@ SQLITE_PRIVATE int sqlite3Select( assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); - if( IgnorableOrderby(pDest) ){ - assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || - pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || - pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo || - pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo); - /* If ORDER BY makes no difference in the output then neither does - ** DISTINCT so it can be removed too. */ + if( IgnorableDistinct(pDest) ){ + assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || + pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || + pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo ); + /* All of these destinations are also able to ignore the ORDER BY clause */ sqlite3ExprListDelete(db, p->pOrderBy); p->pOrderBy = 0; p->selFlags &= ~SF_Distinct; @@ -136547,22 +137077,11 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( pTab = sqlite3SrcListLookup(pParse, pTableName); if( !pTab ){ /* The table does not exist. */ - if( db->init.iDb==1 ){ - /* Ticket #3810. - ** Normally, whenever a table is dropped, all associated triggers are - ** dropped too. But if a TEMP trigger is created on a non-TEMP table - ** and the table is dropped by a different database connection, the - ** trigger is not visible to the database connection that does the - ** drop so the trigger cannot be dropped. This results in an - ** "orphaned trigger" - a trigger whose associated table is missing. - */ - db->init.orphanTrigger = 1; - } - goto trigger_cleanup; + goto trigger_orphan_error; } if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); - goto trigger_cleanup; + goto trigger_orphan_error; } /* Check that the trigger name is not reserved and that no trigger of the @@ -136600,12 +137119,12 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( if( pTab->pSelect && tr_tm!=TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); - goto trigger_cleanup; + goto trigger_orphan_error; } if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" " trigger on table: %S", pTableName, 0); - goto trigger_cleanup; + goto trigger_orphan_error; } #ifndef SQLITE_OMIT_AUTHORIZATION @@ -136665,6 +137184,23 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( }else{ assert( pParse->pNewTrigger==pTrigger ); } + return; + +trigger_orphan_error: + if( db->init.iDb==1 ){ + /* Ticket #3810. + ** Normally, whenever a table is dropped, all associated triggers are + ** dropped too. But if a TEMP trigger is created on a non-TEMP table + ** and the table is dropped by a different database connection, the + ** trigger is not visible to the database connection that does the + ** drop so the trigger cannot be dropped. This results in an + ** "orphaned trigger" - a trigger whose associated table is missing. + ** + ** 2020-11-05 see also https://sqlite.org/forum/forumpost/157dc791df + */ + db->init.orphanTrigger = 1; + } + goto trigger_cleanup; } /* @@ -137835,7 +138371,7 @@ static void updateFromSelect( #endif pList = sqlite3ExprListAppend(pParse, pList, pNew); } - eDest = SRT_Upfrom; + eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom; }else if( pTab->pSelect ){ for(i=0; inCol; i++){ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i)); @@ -138252,6 +138788,8 @@ SQLITE_PRIVATE void sqlite3Update( if( nChangeFrom==0 && HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); + iEph = pParse->nTab++; + addrOpen = sqlite3VdbeAddOp3(v, OP_OpenEphemeral, iEph, 0, regRowSet); }else{ assert( pPk!=0 || HasRowid(pTab) ); nPk = pPk ? pPk->nKeyCol : 0; @@ -138306,7 +138844,7 @@ SQLITE_PRIVATE void sqlite3Update( ** be deleted as a result of REPLACE conflict handling. Any of these ** things might disturb a cursor being used to scan through the table ** or index, causing a single-pass approach to malfunction. */ - flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE; + flags = WHERE_ONEPASS_DESIRED; if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ flags |= WHERE_ONEPASS_MULTIROW; } @@ -138343,9 +138881,10 @@ SQLITE_PRIVATE void sqlite3Update( ** leave it in register regOldRowid. */ sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); if( eOnePass==ONEPASS_OFF ){ - /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */ aRegIdx[nAllIdx] = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); + sqlite3VdbeAddOp3(v, OP_Insert, iEph, regRowSet, regOldRowid); + }else{ + if( ALWAYS(addrOpen) ) sqlite3VdbeChangeToNoop(v, addrOpen); } }else{ /* Read the PK of the current row into an array of registers. In @@ -138433,8 +138972,9 @@ SQLITE_PRIVATE void sqlite3Update( VdbeCoverage(v); } }else{ - labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak, - regOldRowid); + sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); + labelContinue = sqlite3VdbeMakeLabel(pParse); + addrTop = sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); VdbeCoverage(v); @@ -138684,11 +139224,9 @@ SQLITE_PRIVATE void sqlite3Update( }else if( eOnePass==ONEPASS_MULTI ){ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3WhereEnd(pWInfo); - }else if( pPk || nChangeFrom ){ + }else{ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v); - }else{ - sqlite3VdbeGoto(v, labelContinue); } sqlite3VdbeResolveLabel(v, labelBreak); @@ -138788,12 +139326,26 @@ static void updateVirtualTable( regArg = pParse->nMem + 1; pParse->nMem += nArg; if( pSrc->nSrc>1 ){ + Index *pPk = 0; Expr *pRow; ExprList *pList; - if( pRowid ){ - pRow = sqlite3ExprDup(db, pRowid, 0); + if( HasRowid(pTab) ){ + if( pRowid ){ + pRow = sqlite3ExprDup(db, pRowid, 0); + }else{ + pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0); + } }else{ - pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0); + i16 iPk; /* PRIMARY KEY column */ + pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pPk!=0 ); + assert( pPk->nKeyCol==1 ); + iPk = pPk->aiColumn[0]; + if( aXRef[iPk]>=0 ){ + pRow = sqlite3ExprDup(db, pChanges->a[aXRef[iPk]].pExpr, 0); + }else{ + pRow = exprRowColumn(pParse, iPk); + } } pList = sqlite3ExprListAppend(pParse, 0, pRow); @@ -138807,7 +139359,7 @@ static void updateVirtualTable( } } - updateFromSelect(pParse, ephemTab, 0, pList, pSrc, pWhere, 0, 0); + updateFromSelect(pParse, ephemTab, pPk, pList, pSrc, pWhere, 0, 0); sqlite3ExprListDelete(db, pList); eOnePass = ONEPASS_OFF; }else{ @@ -139509,8 +140061,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( BTREE_APPLICATION_ID, 0, /* Preserve the application id */ }; - assert( 1==sqlite3BtreeIsInTrans(pTemp) ); - assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) ); + assert( SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pTemp) ); + assert( pOut!=0 || SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pMain) ); /* Copy Btree meta values */ for(i=0; ia[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X " */ - int iField; /* Field in (?,?,?) IN (SELECT...) vector */ union { - int leftColumn; /* Column number of X in "X " */ + struct { + int leftColumn; /* Column number of X in "X " */ + int iField; /* Field in (?,?,?) IN (SELECT...) vector */ + } x; /* Opcode other than OP_OR or OP_AND */ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; @@ -141408,6 +141962,7 @@ struct WhereInfo { unsigned sorted :1; /* True if really sorted (not just grouped) */ LogEst nRowOut; /* Estimated number of output rows */ int iTop; /* The very beginning of the WHERE loop */ + int iEndWhere; /* End of the WHERE clause itself */ WhereLoop *pLoops; /* List of all WhereLoop objects */ WhereExprMod *pExprMods; /* Expression modifications */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ @@ -141536,6 +142091,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC #define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ #define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ #define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */ +#define WHERE_IN_SEEKSCAN 0x00100000 /* Seek-scan optimization for IN */ #endif /* !defined(SQLITE_WHEREINT_H) */ @@ -141949,7 +142505,7 @@ static Expr *removeUnindexableInClauseTerms( for(i=iEq; inLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ - int iField = pLoop->aLTerm[i]->iField - 1; + int iField = pLoop->aLTerm[i]->u.x.iField - 1; if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */ pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr); pOrigRhs->a[iField].pExpr = 0; @@ -142092,6 +142648,9 @@ static int codeEqualityTerm( if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse); } + if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){ + pLoop->wsFlags |= WHERE_IN_EARLYOUT; + } i = pLevel->u.in.nIn; pLevel->u.in.nIn += nEq; @@ -142118,7 +142677,6 @@ static int codeEqualityTerm( if( iEq>0 ){ pIn->iBase = iReg - i; pIn->nPrefix = i; - pLoop->wsFlags |= WHERE_IN_EARLYOUT; }else{ pIn->nPrefix = 0; } @@ -142128,6 +142686,14 @@ static int codeEqualityTerm( pIn++; } } + testcase( iEq>0 + && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 + && (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ); + if( iEq>0 + && (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0 + ){ + sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq); + } }else{ pLevel->u.in.nIn = 0; } @@ -142914,6 +143480,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC); VdbeCoverage(v); pLoop->u.vtab.needFree = 0; + /* An OOM inside of AddOp4(OP_VFilter) instruction above might have freed + ** the u.vtab.idxStr. NULL it out to prevent a use-after-free */ + if( db->mallocFailed ) pLoop->u.vtab.idxStr = 0; pLevel->p1 = iCur; pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext; pLevel->p2 = sqlite3VdbeCurrentAddr(v); @@ -143172,6 +143741,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ int omitTable; /* True if we use the index only */ int regBignull = 0; /* big-null flag register */ + int addrSeekScan = 0; /* Opcode of the OP_SeekScan, if any */ pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; @@ -143310,9 +143880,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** above has already left the cursor sitting on the correct row, ** so no further seeking is needed */ }else{ - if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){ - sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur); - } if( regBignull ){ sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull); VdbeComment((v, "NULL-scan pass ctr")); @@ -143320,6 +143887,20 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); + if( (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 && op==OP_SeekGE ){ + assert( regBignull==0 ); + /* TUNING: The OP_SeekScan opcode seeks to reduce the number + ** of expensive seek operations by replacing a single seek with + ** 1 or more step operations. The question is, how many steps + ** should we try before giving up and going with a seek. The cost + ** of a seek is proportional to the logarithm of the of the number + ** of entries in the tree, so basing the number of steps to try + ** on the estimated number of rows in the btree seems like a good + ** guess. */ + addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan, + (pIdx->aiRowLogEst[0]+9)/10); + VdbeCoverage(v); + } sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); VdbeCoverage(v); VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); @@ -143402,6 +143983,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); + if( addrSeekScan ) sqlite3VdbeJumpHere(v, addrSeekScan); } if( regBignull ){ /* During a NULL-scan, check to see if we have reached the end of @@ -143421,8 +144003,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); } - if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){ - sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1); + if( (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0 ){ + sqlite3VdbeAddOp3(v, OP_SeekHit, iIdxCur, nEq, nEq); } /* Seek the table cursor, if required */ @@ -143431,17 +144013,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */ }else if( HasRowid(pIdx->pTable) ){ - if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE) - || ( (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE)!=0 - && (pWInfo->eOnePass==ONEPASS_SINGLE || pLoop->nLTerm==0) ) - ){ - iRowidReg = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); - sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg); - VdbeCoverage(v); - }else{ - codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); - } + codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur); }else if( iCur!=iIdxCur ){ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); @@ -143568,7 +144140,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ - u16 wctrlFlags; /* Flags for sub-WHERE clause */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ Table *pTab = pTabItem->pTab; @@ -143669,7 +144240,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ** eliminating duplicates from other WHERE clauses, the action for each ** sub-WHERE clause is to to invoke the main loop body as a subroutine. */ - wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE); ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR")); for(ii=0; iinTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; @@ -143688,7 +144258,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1)); WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, - wctrlFlags, iCovCur); + WHERE_OR_SUBCLAUSE, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; @@ -143786,6 +144356,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( }else{ pCov = 0; } + if( sqlite3WhereUsesDeferredSeek(pSubWInfo) ){ + pWInfo->bDeferredSeek = 1; + } /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); @@ -143938,7 +144511,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( #endif assert( !ExprHasProperty(pE, EP_FromJoin) ); assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); - pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady, + pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady, WO_EQ|WO_IN|WO_IS, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; @@ -144794,7 +145367,7 @@ static void exprAnalyzeOrTerm( assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) ); continue; } - iColumn = pOrTerm->u.leftColumn; + iColumn = pOrTerm->u.x.leftColumn; iCursor = pOrTerm->leftCursor; pLeft = pOrTerm->pExpr->pLeft; break; @@ -144816,7 +145389,7 @@ static void exprAnalyzeOrTerm( assert( pOrTerm->eOperator & WO_EQ ); if( pOrTerm->leftCursor!=iCursor ){ pOrTerm->wtFlags &= ~TERM_OR_OK; - }else if( pOrTerm->u.leftColumn!=iColumn || (iColumn==XN_EXPR + }else if( pOrTerm->u.x.leftColumn!=iColumn || (iColumn==XN_EXPR && sqlite3ExprCompare(pParse, pOrTerm->pExpr->pLeft, pLeft, -1) )){ okToChngToIN = 0; @@ -144851,7 +145424,7 @@ static void exprAnalyzeOrTerm( if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; assert( pOrTerm->eOperator & WO_EQ ); assert( pOrTerm->leftCursor==iCursor ); - assert( pOrTerm->u.leftColumn==iColumn ); + assert( pOrTerm->u.x.leftColumn==iColumn ); pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); pLeft = pOrTerm->pExpr->pLeft; @@ -145087,15 +145660,15 @@ static void exprAnalyze( Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; - if( pTerm->iField>0 ){ + if( pTerm->u.x.iField>0 ){ assert( op==TK_IN ); assert( pLeft->op==TK_VECTOR ); - pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr; + pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr; } if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){ pTerm->leftCursor = aiCurCol[0]; - pTerm->u.leftColumn = aiCurCol[1]; + pTerm->u.x.leftColumn = aiCurCol[1]; pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; @@ -145105,7 +145678,7 @@ static void exprAnalyze( WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ - assert( pTerm->iField==0 ); + assert( pTerm->u.x.iField==0 ); if( pTerm->leftCursor>=0 ){ int idxNew; pDup = sqlite3ExprDup(db, pExpr, 0); @@ -145131,7 +145704,7 @@ static void exprAnalyze( } pNew->wtFlags |= exprCommute(pParse, pDup); pNew->leftCursor = aiCurCol[0]; - pNew->u.leftColumn = aiCurCol[1]; + pNew->u.x.leftColumn = aiCurCol[1]; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; @@ -145305,7 +145878,7 @@ static void exprAnalyze( pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = prereqExpr; pNewTerm->leftCursor = pLeft->iTable; - pNewTerm->u.leftColumn = pLeft->iColumn; + pNewTerm->u.x.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_AUX; pNewTerm->eMatchOp = eOp2; markTermAsChild(pWC, idxNew, idxTerm); @@ -145352,13 +145925,13 @@ static void exprAnalyze( /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create ** a virtual term for each vector component. The expression object ** used by each such virtual term is pExpr (the full vector IN(...) - ** expression). The WhereTerm.iField variable identifies the index within + ** expression). The WhereTerm.u.x.iField variable identifies the index within ** the vector on the LHS that the virtual term represents. ** ** This only works if the RHS is a simple SELECT (not a compound) that does ** not use window functions. */ - if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0 + if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->u.x.iField==0 && pExpr->pLeft->op==TK_VECTOR && pExpr->x.pSelect->pPrior==0 #ifndef SQLITE_OMIT_WINDOWFUNC @@ -145369,7 +145942,7 @@ static void exprAnalyze( for(i=0; ipLeft); i++){ int idxNew; idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL); - pWC->a[idxNew].iField = i+1; + pWC->a[idxNew].u.x.iField = i+1; exprAnalyze(pSrc, pWC, idxNew); markTermAsChild(pWC, idxNew, idxTerm); } @@ -145404,7 +145977,7 @@ static void exprAnalyze( pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = 0; pNewTerm->leftCursor = pLeft->iTable; - pNewTerm->u.leftColumn = pLeft->iColumn; + pNewTerm->u.x.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_GT; markTermAsChild(pWC, idxNew, idxTerm); pTerm = &pWC->a[idxTerm]; @@ -145447,6 +146020,7 @@ static void exprAnalyze( SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr); pWC->op = op; + assert( pE2!=0 || pExpr==0 ); if( pE2==0 ) return; if( pE2->op!=op ){ whereClauseInsert(pWC, pExpr, 0); @@ -145846,6 +146420,16 @@ static void createMask(WhereMaskSet *pMaskSet, int iCursor){ pMaskSet->ix[pMaskSet->n++] = iCursor; } +/* +** If the right-hand branch of the expression is a TK_COLUMN, then return +** a pointer to the right-hand branch. Otherwise, return NULL. +*/ +static Expr *whereRightSubexprIsColumn(Expr *p){ + p = sqlite3ExprSkipCollateAndLikely(p->pRight); + if( ALWAYS(p!=0) && p->op==TK_COLUMN ) return p; + return 0; +} + /* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). @@ -145868,7 +146452,7 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ do{ for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ if( pTerm->leftCursor==iCur - && pTerm->u.leftColumn==iColumn + && pTerm->u.x.leftColumn==iColumn && (iColumn!=XN_EXPR || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft, pScan->pIdxExpr,iCur)==0) @@ -145876,8 +146460,7 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquivaiCur) - && (pX = sqlite3ExprSkipCollateAndLikely(pTerm->pExpr->pRight))->op - ==TK_COLUMN + && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0 ){ int j; for(j=0; jnEquiv; j++){ @@ -146073,7 +146656,8 @@ static int findIndexCol( for(i=0; inExpr; i++){ Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr); - if( p->op==TK_COLUMN + if( ALWAYS(p!=0) + && p->op==TK_COLUMN && p->iColumn==pIdx->aiColumn[iCol] && p->iTable==iBase ){ @@ -146137,6 +146721,7 @@ static int isDistinctRedundant( */ for(i=0; inExpr; i++){ Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr); + if( NEVER(p==0) ) continue; if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1; } @@ -146290,8 +146875,8 @@ static int termCanDriveIndex( return 0; } if( (pTerm->prereqRight & notReady)!=0 ) return 0; - if( pTerm->u.leftColumn<0 ) return 0; - aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; + if( pTerm->u.x.leftColumn<0 ) return 0; + aff = pSrc->pTab->aCol[pTerm->u.x.leftColumn].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; testcase( pTerm->pExpr->op==TK_IS ); return 1; @@ -146362,7 +146947,7 @@ static void constructAutomaticIndex( sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ - int iCol = pTerm->u.leftColumn; + int iCol = pTerm->u.x.leftColumn; Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); @@ -146415,14 +147000,14 @@ static void constructAutomaticIndex( idxCols = 0; for(pTerm=pWC->a; pTermu.leftColumn; + int iCol = pTerm->u.x.leftColumn; Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS-1 ); testcase( iCol==BMS ); if( (idxCols & cMask)==0 ){ Expr *pX = pTerm->pExpr; idxCols |= cMask; - pIdx->aiColumn[n] = pTerm->u.leftColumn; + pIdx->aiColumn[n] = pTerm->u.x.leftColumn; pColl = sqlite3ExprCompareCollSeq(pParse, pX); assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */ pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY; @@ -146543,7 +147128,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; - assert( pTerm->u.leftColumn>=(-1) ); + assert( pTerm->u.x.leftColumn>=(-1) ); nTerm++; } @@ -146603,8 +147188,8 @@ static sqlite3_index_info *allocateIndexInfo( ){ continue; } - assert( pTerm->u.leftColumn>=(-1) ); - pIdxCons[j].iColumn = pTerm->u.leftColumn; + assert( pTerm->u.x.leftColumn>=(-1) ); + pIdxCons[j].iColumn = pTerm->u.x.leftColumn; pIdxCons[j].iTermOffset = i; op = pTerm->eOperator & WO_ALL; if( op==WO_IN ) op = WO_EQ; @@ -147367,9 +147952,9 @@ SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm->wtFlags & TERM_CODED ) zType[3] = 'C'; if( pTerm->eOperator & WO_SINGLE ){ sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", - pTerm->leftCursor, pTerm->u.leftColumn); + pTerm->leftCursor, pTerm->u.x.leftColumn); }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ - sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", + sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%llx", pTerm->u.pOrInfo->indexable); }else{ sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); @@ -147383,8 +147968,8 @@ SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ sqlite3DebugPrintf(" prob=%-3d prereq=%llx,%llx", pTerm->truthProb, (u64)pTerm->prereqAll, (u64)pTerm->prereqRight); } - if( pTerm->iField ){ - sqlite3DebugPrintf(" iField=%d", pTerm->iField); + if( pTerm->u.x.iField ){ + sqlite3DebugPrintf(" iField=%d", pTerm->u.x.iField); } if( pTerm->iParent>=0 ){ sqlite3DebugPrintf(" iParent=%d", pTerm->iParent); @@ -148051,9 +148636,9 @@ static int whereLoopAddBtreeIndex( pNew = pBuilder->pNew; if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; - WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d\n", + WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n", pProbe->pTable->zName,pProbe->zName, - pNew->u.btree.nEq, pNew->nSkip)); + pNew->u.btree.nEq, pNew->nSkip, pNew->rRun)); assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); @@ -148147,7 +148732,7 @@ static int whereLoopAddBtreeIndex( /* "x IN (value, value, ...)" */ nIn = sqlite3LogEst(pExpr->x.pList->nExpr); } - if( pProbe->hasStat1 ){ + if( pProbe->hasStat1 && rLogSize>=10 ){ LogEst M, logK, safetyMargin; /* Let: ** N = the total number of rows in the table @@ -148166,7 +148751,8 @@ static int whereLoopAddBtreeIndex( ** a safety margin of 2 (LogEst: 10) that favors using the IN operator ** with the index, as using an index has better worst-case behavior. ** If we do not have real sqlite_stat1 data, always prefer to use - ** the index. + ** the index. Do not bother with this optimization on very small + ** tables (less than 2 rows) as it is pointless in that case. */ M = pProbe->aiRowLogEst[saved_nEq]; logK = estLog(nIn); @@ -148175,7 +148761,7 @@ static int whereLoopAddBtreeIndex( WHERETRACE(0x40, ("Scan preferred over IN operator on column %d of \"%s\" (%d<%d)\n", saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize)); - continue; + pNew->wsFlags |= WHERE_IN_SEEKSCAN; }else{ WHERETRACE(0x40, ("IN operator preferred on column %d of \"%s\" (%d>=%d)\n", @@ -148421,6 +149007,7 @@ static int indexMightHelpWithOrderBy( if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; for(ii=0; iinExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr); + if( NEVER(pExpr==0) ) continue; if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ if( pExpr->iColumn<0 ) return 1; for(jj=0; jjnKeyCol; jj++){ @@ -148652,8 +149239,23 @@ static int whereLoopAddBtree( /* Full table scan */ pNew->iSortIdx = b ? iSortIdx : 0; - /* TUNING: Cost of full table scan is (N*3.0). */ + /* TUNING: Cost of full table scan is 3.0*N. The 3.0 factor is an + ** extra cost designed to discourage the use of full table scans, + ** since index lookups have better worst-case performance if our + ** stat guesses are wrong. Reduce the 3.0 penalty slightly + ** (to 2.75) if we have valid STAT4 information for the table. + ** At 2.75, a full table scan is preferred over using an index on + ** a column with just two distinct values where each value has about + ** an equal number of appearances. Without STAT4 data, we still want + ** to use an index in that case, since the constraint might be for + ** the scarcer of the two values, and in that case an index lookup is + ** better. + */ +#ifdef SQLITE_ENABLE_STAT4 + pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0); +#else pNew->rRun = rSize + 16; +#endif ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); @@ -149384,6 +149986,7 @@ static i8 wherePathSatisfiesOrderBy( for(i=0; ia[i].pExpr); + if( NEVER(pOBExpr==0) ) continue; if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, @@ -149510,6 +150113,7 @@ static i8 wherePathSatisfiesOrderBy( pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr); testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); + if( NEVER(pOBExpr==0) ) continue; if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; if( iColumn>=XN_ROWID ){ if( pOBExpr->op!=TK_COLUMN ) continue; @@ -149664,16 +150268,24 @@ static LogEst whereSortingCost( ** cost = (3.0 * N * log(N)) * (Y/X) ** ** The (Y/X) term is implemented using stack variable rScale - ** below. */ + ** below. + */ LogEst rScale, rSortCost; assert( nOrderBy>0 && 66==sqlite3LogEst(100) ); rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; rSortCost = nRow + rScale + 16; /* Multiple by log(M) where M is the number of output rows. - ** Use the LIMIT for M if it is smaller */ + ** Use the LIMIT for M if it is smaller. Or if this sort is for + ** a DISTINCT operator, M will be the number of distinct output + ** rows, so fudge it downwards a bit. + */ if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimitiLimit; + }else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){ + /* TUNING: In the sort for a DISTINCT operator, assume that the DISTINCT + ** reduces the number of output rows by a factor of 2 */ + if( nRow>10 ) nRow -= 10; assert( 10==sqlite3LogEst(2) ); } rSortCost += estLog(nRow); return rSortCost; @@ -150800,6 +151412,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0 && (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0 && (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0 + && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED ){ @@ -150857,6 +151470,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin( /* Done. */ VdbeModuleComment((v, "Begin WHERE-core")); + pWInfo->iEndWhere = sqlite3VdbeCurrentAddr(v); return pWInfo; /* Jump here if malloc fails */ @@ -150900,6 +151514,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ WhereLoop *pLoop; SrcList *pTabList = pWInfo->pTabList; sqlite3 *db = pParse->db; + int iEnd = sqlite3VdbeCurrentAddr(v); /* Generate loop termination code. */ @@ -150960,7 +151575,9 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); if( pIn->eEndLoopOp!=OP_Noop ){ if( pIn->nPrefix ){ - assert( pLoop->wsFlags & WHERE_IN_EARLYOUT ); + int bEarlyOut = + (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 + && (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0; if( pLevel->iLeftJoin ){ /* For LEFT JOIN queries, cursor pIn->iCur may not have been ** opened yet. This occurs for WHERE clauses such as @@ -150971,12 +151588,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ** jump over the OP_Next or OP_Prev instruction about to ** be coded. */ sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur, - sqlite3VdbeCurrentAddr(v) + 2 + - ((pLoop->wsFlags & WHERE_VIRTUALTABLE)==0) - ); + sqlite3VdbeCurrentAddr(v) + 2 + bEarlyOut); VdbeCoverage(v); } - if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){ + if( bEarlyOut ){ sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur, sqlite3VdbeCurrentAddr(v)+2, pIn->iBase, pIn->nPrefix); @@ -151037,7 +151652,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ assert( pWInfo->nLevel<=pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ int k, last; - VdbeOp *pOp; + VdbeOp *pOp, *pLastOp; Index *pIdx = 0; struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; Table *pTab = pTabItem->pTab; @@ -151095,20 +151710,31 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ pIdx = pLevel->u.pCovidx; } if( pIdx - && (pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable)) && !db->mallocFailed ){ - last = sqlite3VdbeCurrentAddr(v); - k = pLevel->addrBody; + if( pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable) ){ + last = iEnd; + }else{ + last = pWInfo->iEndWhere; + } + k = pLevel->addrBody + 1; #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeAddopTrace ){ printf("TRANSLATE opcodes in range %d..%d\n", k, last-1); } + /* Proof that the "+1" on the k value above is safe */ + pOp = sqlite3VdbeGetOp(v, k - 1); + assert( pOp->opcode!=OP_Column || pOp->p1!=pLevel->iTabCur ); + assert( pOp->opcode!=OP_Rowid || pOp->p1!=pLevel->iTabCur ); + assert( pOp->opcode!=OP_IfNullRow || pOp->p1!=pLevel->iTabCur ); #endif pOp = sqlite3VdbeGetOp(v, k); - for(; kp1!=pLevel->iTabCur ) continue; - if( pOp->opcode==OP_Column + pLastOp = pOp + (last - k); + assert( pOpp1!=pLevel->iTabCur ){ + /* no-op */ + }else if( pOp->opcode==OP_Column #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC || pOp->opcode==OP_Offset #endif @@ -151139,7 +151765,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ pOp->p1 = pLevel->iIdxCur; OpcodeRewriteTrace(db, k, pOp); } - } +#ifdef SQLITE_DEBUG + k++; +#endif + }while( (++pOp)flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n"); #endif @@ -154208,8 +154837,10 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( /************** End of window.c **********************************************/ /************** Begin file parse.c *******************************************/ +/* This file is automatically generated by Lemon from input grammar +** source file "parse.y". */ /* -** 2000-05-29 +** 2001-09-15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -154219,22 +154850,15 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( ** May you share freely, never taking more than you give. ** ************************************************************************* -** Driver template for the LEMON parser generator. -** -** The "lemon" program processes an LALR(1) input grammar file, then uses -** this template to construct a parser. The "lemon" program inserts text -** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the -** interstitial "-" characters) contained in this template is changed into -** the value of the %name directive from the grammar. Otherwise, the content -** of this template is copied straight through into the generate parser -** source file. +** This file contains SQLite's SQL parser. ** -** The following is the concatenation of all %include directives from the -** input grammar file: +** The canonical source code to this file ("parse.y") is a Lemon grammar +** file that specifies the input grammar and actions to take while parsing. +** That input file is processed by Lemon to generate a C-language +** implementation of a parser for the given grammer. You might be reading +** this comment as part of the translated C-code. Edits should be made +** to the original parse.y sources. */ -/* #include */ -/* #include */ -/************ Begin %include sections from the grammar ************************/ /* #include "sqliteInt.h" */ @@ -154418,11 +155042,191 @@ static void updateDeleteLimitError( # error too many tokens in the grammar #endif /**************** End of %include directives **********************************/ -/* These constants specify the various numeric values for terminal symbols -** in a format understandable to "makeheaders". This section is blank unless -** "lemon" is run with the "-m" command-line option. -***************** Begin makeheaders token definitions *************************/ -/**************** End makeheaders token definitions ***************************/ +/* These constants specify the various numeric values for terminal symbols. +***************** Begin token definitions *************************************/ +#ifndef TK_SEMI +#define TK_SEMI 1 +#define TK_EXPLAIN 2 +#define TK_QUERY 3 +#define TK_PLAN 4 +#define TK_BEGIN 5 +#define TK_TRANSACTION 6 +#define TK_DEFERRED 7 +#define TK_IMMEDIATE 8 +#define TK_EXCLUSIVE 9 +#define TK_COMMIT 10 +#define TK_END 11 +#define TK_ROLLBACK 12 +#define TK_SAVEPOINT 13 +#define TK_RELEASE 14 +#define TK_TO 15 +#define TK_TABLE 16 +#define TK_CREATE 17 +#define TK_IF 18 +#define TK_NOT 19 +#define TK_EXISTS 20 +#define TK_TEMP 21 +#define TK_LP 22 +#define TK_RP 23 +#define TK_AS 24 +#define TK_WITHOUT 25 +#define TK_COMMA 26 +#define TK_ABORT 27 +#define TK_ACTION 28 +#define TK_AFTER 29 +#define TK_ANALYZE 30 +#define TK_ASC 31 +#define TK_ATTACH 32 +#define TK_BEFORE 33 +#define TK_BY 34 +#define TK_CASCADE 35 +#define TK_CAST 36 +#define TK_CONFLICT 37 +#define TK_DATABASE 38 +#define TK_DESC 39 +#define TK_DETACH 40 +#define TK_EACH 41 +#define TK_FAIL 42 +#define TK_OR 43 +#define TK_AND 44 +#define TK_IS 45 +#define TK_MATCH 46 +#define TK_LIKE_KW 47 +#define TK_BETWEEN 48 +#define TK_IN 49 +#define TK_ISNULL 50 +#define TK_NOTNULL 51 +#define TK_NE 52 +#define TK_EQ 53 +#define TK_GT 54 +#define TK_LE 55 +#define TK_LT 56 +#define TK_GE 57 +#define TK_ESCAPE 58 +#define TK_ID 59 +#define TK_COLUMNKW 60 +#define TK_DO 61 +#define TK_FOR 62 +#define TK_IGNORE 63 +#define TK_INITIALLY 64 +#define TK_INSTEAD 65 +#define TK_NO 66 +#define TK_KEY 67 +#define TK_OF 68 +#define TK_OFFSET 69 +#define TK_PRAGMA 70 +#define TK_RAISE 71 +#define TK_RECURSIVE 72 +#define TK_REPLACE 73 +#define TK_RESTRICT 74 +#define TK_ROW 75 +#define TK_ROWS 76 +#define TK_TRIGGER 77 +#define TK_VACUUM 78 +#define TK_VIEW 79 +#define TK_VIRTUAL 80 +#define TK_WITH 81 +#define TK_NULLS 82 +#define TK_FIRST 83 +#define TK_LAST 84 +#define TK_CURRENT 85 +#define TK_FOLLOWING 86 +#define TK_PARTITION 87 +#define TK_PRECEDING 88 +#define TK_RANGE 89 +#define TK_UNBOUNDED 90 +#define TK_EXCLUDE 91 +#define TK_GROUPS 92 +#define TK_OTHERS 93 +#define TK_TIES 94 +#define TK_GENERATED 95 +#define TK_ALWAYS 96 +#define TK_REINDEX 97 +#define TK_RENAME 98 +#define TK_CTIME_KW 99 +#define TK_ANY 100 +#define TK_BITAND 101 +#define TK_BITOR 102 +#define TK_LSHIFT 103 +#define TK_RSHIFT 104 +#define TK_PLUS 105 +#define TK_MINUS 106 +#define TK_STAR 107 +#define TK_SLASH 108 +#define TK_REM 109 +#define TK_CONCAT 110 +#define TK_COLLATE 111 +#define TK_BITNOT 112 +#define TK_ON 113 +#define TK_INDEXED 114 +#define TK_STRING 115 +#define TK_JOIN_KW 116 +#define TK_CONSTRAINT 117 +#define TK_DEFAULT 118 +#define TK_NULL 119 +#define TK_PRIMARY 120 +#define TK_UNIQUE 121 +#define TK_CHECK 122 +#define TK_REFERENCES 123 +#define TK_AUTOINCR 124 +#define TK_INSERT 125 +#define TK_DELETE 126 +#define TK_UPDATE 127 +#define TK_SET 128 +#define TK_DEFERRABLE 129 +#define TK_FOREIGN 130 +#define TK_DROP 131 +#define TK_UNION 132 +#define TK_ALL 133 +#define TK_EXCEPT 134 +#define TK_INTERSECT 135 +#define TK_SELECT 136 +#define TK_VALUES 137 +#define TK_DISTINCT 138 +#define TK_DOT 139 +#define TK_FROM 140 +#define TK_JOIN 141 +#define TK_USING 142 +#define TK_ORDER 143 +#define TK_GROUP 144 +#define TK_HAVING 145 +#define TK_LIMIT 146 +#define TK_WHERE 147 +#define TK_INTO 148 +#define TK_NOTHING 149 +#define TK_FLOAT 150 +#define TK_BLOB 151 +#define TK_INTEGER 152 +#define TK_VARIABLE 153 +#define TK_CASE 154 +#define TK_WHEN 155 +#define TK_THEN 156 +#define TK_ELSE 157 +#define TK_INDEX 158 +#define TK_ALTER 159 +#define TK_ADD 160 +#define TK_WINDOW 161 +#define TK_OVER 162 +#define TK_FILTER 163 +#define TK_COLUMN 164 +#define TK_AGG_FUNCTION 165 +#define TK_AGG_COLUMN 166 +#define TK_TRUEFALSE 167 +#define TK_ISNOT 168 +#define TK_FUNCTION 169 +#define TK_UMINUS 170 +#define TK_UPLUS 171 +#define TK_TRUTH 172 +#define TK_REGISTER 173 +#define TK_VECTOR 174 +#define TK_SELECT_COLUMN 175 +#define TK_IF_NULL_ROW 176 +#define TK_ASTERISK 177 +#define TK_SPAN 178 +#define TK_SPACE 179 +#define TK_ILLEGAL 180 +#endif +/**************** End token definitions ***************************************/ /* The next sections is a series of control #defines. ** various aspects of the generated parser. @@ -155428,6 +156232,7 @@ typedef struct yyParser yyParser; #ifndef NDEBUG /* #include */ +/* #include */ static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ @@ -156547,7 +157352,7 @@ static YYACTIONTYPE yy_find_shift_action( #endif /* YYWILDCARD */ return yy_default[stateno]; }else{ - assert( i>=0 && i=0 && i<(int)(sizeof(yy_action)/sizeof(yy_action[0])) ); return yy_action[i]; } }while(1); @@ -157475,8 +158280,9 @@ static YYACTIONTYPE yy_reduce( (void)yyLookahead; (void)yyLookaheadToken; yymsp = yypParser->yytos; + assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ); #ifndef NDEBUG - if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ + if( yyTraceFILE ){ yysize = yyRuleInfoNRhs[yyruleno]; if( yysize ){ fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n", @@ -157695,7 +158501,7 @@ static YYACTIONTYPE yy_reduce( SQLITE_IDXTYPE_UNIQUE);} break; case 39: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy202);} +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy202,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} break; case 40: /* ccons ::= REFERENCES nm eidlist_opt refargs */ {sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy242,yymsp[0].minor.yy192);} @@ -157774,7 +158580,7 @@ static YYACTIONTYPE yy_reduce( SQLITE_IDXTYPE_UNIQUE);} break; case 68: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy202);} +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy202,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} break; case 69: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { @@ -161896,7 +162702,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){ sqlite3BtreeEnterAll(db); for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( pBt && sqlite3BtreeIsInTrans(pBt) ){ + if( pBt && sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ Pager *pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerFlush(pPager); if( rc==SQLITE_BUSY ){ @@ -162240,6 +163046,36 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){ return SQLITE_OK; } +/* +** Return the transaction state for a single databse, or the maximum +** transaction state over all attached databases if zSchema is null. +*/ +SQLITE_API int sqlite3_txn_state(sqlite3 *db, const char *zSchema){ + int iDb, nDb; + int iTxn = -1; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return -1; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( zSchema ){ + nDb = iDb = sqlite3FindDbName(db, zSchema); + if( iDb<0 ) nDb--; + }else{ + iDb = 0; + nDb = db->nDb-1; + } + for(; iDb<=nDb; iDb++){ + Btree *pBt = db->aDb[iDb].pBt; + int x = pBt!=0 ? sqlite3BtreeTxnState(pBt) : SQLITE_TXN_NONE; + if( x>iTxn ) iTxn = x; + } + sqlite3_mutex_leave(db->mutex); + return iTxn; +} + /* ** Two variations on the public interface for closing a database ** connection. The sqlite3_close() version returns SQLITE_BUSY and @@ -162400,7 +163236,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){ for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; if( p ){ - if( sqlite3BtreeIsInTrans(p) ){ + if( sqlite3BtreeTxnState(p)==SQLITE_TXN_WRITE ){ inTrans = 1; } sqlite3BtreeRollback(p, tripCode, !schemaChange); @@ -164821,7 +165657,9 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo } rc = SQLITE_OK; }else{ + int nSave = db->busyHandler.nBusy; rc = sqlite3OsFileControl(fd, op, pArg); + db->busyHandler.nBusy = nSave; } sqlite3BtreeLeave(pBtree); } @@ -165204,6 +166042,25 @@ SQLITE_API int sqlite3_test_control(int op, ...){ sqlite3ResultIntReal(pCtx); break; } + + /* sqlite3_test_control(SQLITE_TESTCTRL_SEEK_COUNT, + ** sqlite3 *db, // Database connection + ** u64 *pnSeek // Write seek count here + ** ); + ** + ** This test-control queries the seek-counter on the "main" database + ** file. The seek-counter is written into *pnSeek and is then reset. + ** The seek-count is only available if compiled with SQLITE_DEBUG. + */ + case SQLITE_TESTCTRL_SEEK_COUNT: { + sqlite3 *db = va_arg(ap, sqlite3*); + u64 *pn = va_arg(ap, sqlite3_uint64*); + *pn = sqlite3BtreeSeekCount(db->aDb->pBt); + (void)db; /* Silence harmless unused variable warning */ + break; + } + + } va_end(ap); #endif /* SQLITE_UNTESTABLE */ @@ -165439,7 +166296,7 @@ SQLITE_API int sqlite3_snapshot_get( int iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; - if( 0==sqlite3BtreeIsInTrans(pBt) ){ + if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); @@ -165475,10 +166332,10 @@ SQLITE_API int sqlite3_snapshot_open( iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; - if( sqlite3BtreeIsInTrans(pBt)==0 ){ + if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ){ Pager *pPager = sqlite3BtreePager(pBt); int bUnlock = 0; - if( sqlite3BtreeIsInReadTrans(pBt) ){ + if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_NONE ){ if( db->nVdbeActive==0 ){ rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot); if( rc==SQLITE_OK ){ @@ -165527,7 +166384,7 @@ SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; - if( 0==sqlite3BtreeIsInReadTrans(pBt) ){ + if( SQLITE_TXN_NONE==sqlite3BtreeTxnState(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt)); @@ -188818,7 +189675,7 @@ static int nodeAcquire( ** are the leaves, and so on. If the depth as specified on the root node ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. */ - if( pNode && iNode==1 ){ + if( pNode && rc==SQLITE_OK && iNode==1 ){ pRtree->iDepth = readInt16(pNode->zData); if( pRtree->iDepth>RTREE_MAX_DEPTH ){ rc = SQLITE_CORRUPT_VTAB; @@ -193504,7 +194361,7 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){ geopolyAddSegments(p, p1, 1); geopolyAddSegments(p, p2, 2); pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent); - rX = pThisEvent->x==0.0 ? -1.0 : 0.0; + rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0; memset(aOverlap, 0, sizeof(aOverlap)); while( pThisEvent ){ if( pThisEvent->x!=rX ){ @@ -208687,6 +209544,7 @@ struct Fts5Config { Fts5Tokenizer *pTok; fts5_tokenizer *pTokApi; int bLock; /* True when table is preparing statement */ + int ePattern; /* FTS_PATTERN_XXX constant */ /* Values loaded from the %_config table */ int iCookie; /* Incremented when %_config is modified */ @@ -208707,17 +209565,19 @@ struct Fts5Config { }; /* Current expected value of %_config table 'version' field */ -#define FTS5_CURRENT_VERSION 4 +#define FTS5_CURRENT_VERSION 4 #define FTS5_CONTENT_NORMAL 0 #define FTS5_CONTENT_NONE 1 #define FTS5_CONTENT_EXTERNAL 2 -#define FTS5_DETAIL_FULL 0 -#define FTS5_DETAIL_NONE 1 -#define FTS5_DETAIL_COLUMNS 2 - +#define FTS5_DETAIL_FULL 0 +#define FTS5_DETAIL_NONE 1 +#define FTS5_DETAIL_COLUMNS 2 +#define FTS5_PATTERN_NONE 0 +#define FTS5_PATTERN_LIKE 65 /* matches SQLITE_INDEX_CONSTRAINT_LIKE */ +#define FTS5_PATTERN_GLOB 66 /* matches SQLITE_INDEX_CONSTRAINT_GLOB */ static int sqlite3Fts5ConfigParse( Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char** @@ -208987,7 +209847,7 @@ static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int); /* ** Functions called by the storage module as part of integrity-check. */ -static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum); +static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum, int bUseCksum); /* ** Called during virtual module initialization to register UDF @@ -209057,8 +209917,7 @@ static int sqlite3Fts5GetTokenizer( Fts5Global*, const char **azArg, int nArg, - Fts5Tokenizer**, - fts5_tokenizer**, + Fts5Config*, char **pzErr ); @@ -209142,7 +210001,7 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); -static int sqlite3Fts5StorageIntegrity(Fts5Storage *p); +static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg); static int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**); static void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*); @@ -209187,11 +210046,19 @@ struct Fts5Token { /* Parse a MATCH expression. */ static int sqlite3Fts5ExprNew( Fts5Config *pConfig, + int bPhraseToAnd, int iCol, /* Column on LHS of MATCH operator */ const char *zExpr, Fts5Expr **ppNew, char **pzErr ); +static int sqlite3Fts5ExprPattern( + Fts5Config *pConfig, + int bGlob, + int iCol, + const char *zText, + Fts5Expr **pp +); /* ** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc); @@ -209300,6 +210167,10 @@ static int sqlite3Fts5AuxInit(fts5_api*); */ static int sqlite3Fts5TokenizerInit(fts5_api*); +static int sqlite3Fts5TokenizerPattern( + int (*xCreate)(void*, const char**, int, Fts5Tokenizer**), + Fts5Tokenizer *pTok +); /* ** End of interface to code in fts5_tokenizer.c. **************************************************************************/ @@ -209346,6 +210217,8 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*); #define FTS5_PLUS 14 #define FTS5_STAR 15 +/* This file is automatically generated by Lemon from input grammar +** source file "fts5parse.y". */ /* ** 2000-05-29 ** @@ -209370,8 +210243,6 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*); ** The following is the concatenation of all %include directives from the ** input grammar file: */ -/* #include */ -/* #include */ /************ Begin %include sections from the grammar ************************/ /* #include "fts5Int.h" */ @@ -209401,11 +210272,26 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*); #define fts5YYMALLOCARGTYPE u64 /**************** End of %include directives **********************************/ -/* These constants specify the various numeric values for terminal symbols -** in a format understandable to "makeheaders". This section is blank unless -** "lemon" is run with the "-m" command-line option. -***************** Begin makeheaders token definitions *************************/ -/**************** End makeheaders token definitions ***************************/ +/* These constants specify the various numeric values for terminal symbols. +***************** Begin token definitions *************************************/ +#ifndef FTS5_OR +#define FTS5_OR 1 +#define FTS5_AND 2 +#define FTS5_NOT 3 +#define FTS5_TERM 4 +#define FTS5_COLON 5 +#define FTS5_MINUS 6 +#define FTS5_LCP 7 +#define FTS5_RCP 8 +#define FTS5_STRING 9 +#define FTS5_LP 10 +#define FTS5_RP 11 +#define FTS5_CARET 12 +#define FTS5_COMMA 13 +#define FTS5_PLUS 14 +#define FTS5_STAR 15 +#endif +/**************** End token definitions ***************************************/ /* The next sections is a series of control #defines. ** various aspects of the generated parser. @@ -209688,6 +210574,7 @@ typedef struct fts5yyParser fts5yyParser; #ifndef NDEBUG /* #include */ +/* #include */ static FILE *fts5yyTraceFILE = 0; static char *fts5yyTracePrompt = 0; #endif /* NDEBUG */ @@ -210102,7 +210989,7 @@ static fts5YYACTIONTYPE fts5yy_find_shift_action( #endif /* fts5YYWILDCARD */ return fts5yy_default[stateno]; }else{ - assert( i>=0 && i=0 && i<(int)(sizeof(fts5yy_action)/sizeof(fts5yy_action[0])) ); return fts5yy_action[i]; } }while(1); @@ -210316,8 +211203,9 @@ static fts5YYACTIONTYPE fts5yy_reduce( (void)fts5yyLookahead; (void)fts5yyLookaheadToken; fts5yymsp = fts5yypParser->fts5yytos; + assert( fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ); #ifndef NDEBUG - if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){ + if( fts5yyTraceFILE ){ fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno]; if( fts5yysize ){ fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n", @@ -211382,7 +212270,7 @@ static int fts5Bm25GetData( int rc = SQLITE_OK; /* Return code */ Fts5Bm25Data *p; /* Object to return */ - p = pApi->xGetAuxdata(pFts, 0); + p = (Fts5Bm25Data*)pApi->xGetAuxdata(pFts, 0); if( p==0 ){ int nPhrase; /* Number of phrases in query */ sqlite3_int64 nRow = 0; /* Number of rows in table */ @@ -211456,7 +212344,7 @@ static void fts5Bm25Function( ){ const double k1 = 1.2; /* Constant "k1" from BM25 formula */ const double b = 0.75; /* Constant "b" from BM25 formula */ - int rc = SQLITE_OK; /* Error code */ + int rc; /* Error code */ double score = 0.0; /* SQL function return value */ Fts5Bm25Data *pData; /* Values allocated/calculated once only */ int i; /* Iterator variable */ @@ -211488,17 +212376,15 @@ static void fts5Bm25Function( D = (double)nTok; } - /* Determine the BM25 score for the current row. */ - for(i=0; rc==SQLITE_OK && inPhrase; i++){ - score += pData->aIDF[i] * ( - ( aFreq[i] * (k1 + 1.0) ) / - ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) ) - ); - } - - /* If no error has occurred, return the calculated score. Otherwise, - ** throw an SQL exception. */ + /* Determine and return the BM25 score for the current row. Or, if an + ** error has occurred, throw an exception. */ if( rc==SQLITE_OK ){ + for(i=0; inPhrase; i++){ + score += pData->aIDF[i] * ( + ( aFreq[i] * (k1 + 1.0) ) / + ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) ) + ); + } sqlite3_result_double(pCtx, -1.0 * score); }else{ sqlite3_result_error_code(pCtx, rc); @@ -212262,7 +213148,7 @@ static int fts5ConfigParseSpecial( rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5GetTokenizer(pGlobal, - (const char**)azArg, (int)nArg, &pConfig->pTok, &pConfig->pTokApi, + (const char**)azArg, (int)nArg, pConfig, pzErr ); } @@ -212334,9 +213220,7 @@ static int fts5ConfigParseSpecial( */ static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){ assert( pConfig->pTok==0 && pConfig->pTokApi==0 ); - return sqlite3Fts5GetTokenizer( - pGlobal, 0, 0, &pConfig->pTok, &pConfig->pTokApi, 0 - ); + return sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0); } /* @@ -213028,6 +213912,7 @@ struct Fts5Parse { int nPhrase; /* Size of apPhrase array */ Fts5ExprPhrase **apPhrase; /* Array of all phrases */ Fts5ExprNode *pExpr; /* Result of a successful parse */ + int bPhraseToAnd; /* Convert "a+b" to "a AND b" */ }; static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){ @@ -213116,6 +214001,7 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); } static int sqlite3Fts5ExprNew( Fts5Config *pConfig, /* FTS5 Configuration */ + int bPhraseToAnd, int iCol, const char *zExpr, /* Expression text */ Fts5Expr **ppNew, @@ -213131,6 +214017,7 @@ static int sqlite3Fts5ExprNew( *ppNew = 0; *pzErr = 0; memset(&sParse, 0, sizeof(sParse)); + sParse.bPhraseToAnd = bPhraseToAnd; pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc); if( pEngine==0 ){ return SQLITE_NOMEM; } sParse.pConfig = pConfig; @@ -213173,6 +214060,7 @@ static int sqlite3Fts5ExprNew( pNew->pConfig = pConfig; pNew->apExprPhrase = sParse.apPhrase; pNew->nPhrase = sParse.nPhrase; + pNew->bDesc = 0; sParse.apPhrase = 0; } }else{ @@ -213184,6 +214072,81 @@ static int sqlite3Fts5ExprNew( return sParse.rc; } +/* +** This function is only called when using the special 'trigram' tokenizer. +** Argument zText contains the text of a LIKE or GLOB pattern matched +** against column iCol. This function creates and compiles an FTS5 MATCH +** expression that will match a superset of the rows matched by the LIKE or +** GLOB. If successful, SQLITE_OK is returned. Otherwise, an SQLite error +** code. +*/ +static int sqlite3Fts5ExprPattern( + Fts5Config *pConfig, int bGlob, int iCol, const char *zText, Fts5Expr **pp +){ + i64 nText = strlen(zText); + char *zExpr = (char*)sqlite3_malloc64(nText*4 + 1); + int rc = SQLITE_OK; + + if( zExpr==0 ){ + rc = SQLITE_NOMEM; + }else{ + char aSpec[3]; + int iOut = 0; + int i = 0; + int iFirst = 0; + + if( bGlob==0 ){ + aSpec[0] = '_'; + aSpec[1] = '%'; + aSpec[2] = 0; + }else{ + aSpec[0] = '*'; + aSpec[1] = '?'; + aSpec[2] = '['; + } + + while( i<=nText ){ + if( i==nText + || zText[i]==aSpec[0] || zText[i]==aSpec[1] || zText[i]==aSpec[2] + ){ + if( i-iFirst>=3 ){ + int jj; + zExpr[iOut++] = '"'; + for(jj=iFirst; jj0 ){ + int bAnd = 0; + if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ + bAnd = 1; + if( pConfig->eDetail==FTS5_DETAIL_NONE ){ + iCol = pConfig->nCol; + } + } + zExpr[iOut] = '\0'; + rc = sqlite3Fts5ExprNew(pConfig, bAnd, iCol, zExpr, pp,pConfig->pzErrmsg); + }else{ + *pp = 0; + } + sqlite3_free(zExpr); + } + + return rc; +} + /* ** Free the expression node object passed as the only argument. */ @@ -214561,6 +215524,20 @@ static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){ pParse->pExpr = p; } +static int parseGrowPhraseArray(Fts5Parse *pParse){ + if( (pParse->nPhrase % 8)==0 ){ + sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); + Fts5ExprPhrase **apNew; + apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte); + if( apNew==0 ){ + pParse->rc = SQLITE_NOMEM; + return SQLITE_NOMEM; + } + pParse->apPhrase = apNew; + } + return SQLITE_OK; +} + /* ** This function is called by the parser to process a string token. The ** string may or may not be quoted. In any case it is tokenized and a @@ -214596,16 +215573,9 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm( }else{ if( pAppend==0 ){ - if( (pParse->nPhrase % 8)==0 ){ - sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8); - Fts5ExprPhrase **apNew; - apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte); - if( apNew==0 ){ - pParse->rc = SQLITE_NOMEM; - fts5ExprPhraseFree(sCtx.pPhrase); - return 0; - } - pParse->apPhrase = apNew; + if( parseGrowPhraseArray(pParse) ){ + fts5ExprPhraseFree(sCtx.pPhrase); + return 0; } pParse->nPhrase++; } @@ -215012,6 +215982,67 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){ } } +/* +** This function is used when parsing LIKE or GLOB patterns against +** trigram indexes that specify either detail=column or detail=none. +** It converts a phrase: +** +** abc + def + ghi +** +** into an AND tree: +** +** abc AND def AND ghi +*/ +static Fts5ExprNode *fts5ParsePhraseToAnd( + Fts5Parse *pParse, + Fts5ExprNearset *pNear +){ + int nTerm = pNear->apPhrase[0]->nTerm; + int ii; + int nByte; + Fts5ExprNode *pRet; + + assert( pNear->nPhrase==1 ); + assert( pParse->bPhraseToAnd ); + + nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*); + pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); + if( pRet ){ + pRet->eType = FTS5_AND; + pRet->nChild = nTerm; + fts5ExprAssignXNext(pRet); + pParse->nPhrase--; + for(ii=0; iirc, sizeof(Fts5ExprPhrase) + ); + if( pPhrase ){ + if( parseGrowPhraseArray(pParse) ){ + fts5ExprPhraseFree(pPhrase); + }else{ + pParse->apPhrase[pParse->nPhrase++] = pPhrase; + pPhrase->nTerm = 1; + pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup( + &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1 + ); + pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING, + 0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase) + ); + } + } + } + + if( pParse->rc ){ + sqlite3Fts5ParseNodeFree(pRet); + pRet = 0; + }else{ + sqlite3Fts5ParseNearsetFree(pNear); + } + } + + return pRet; +} + /* ** Allocate and return a new expression object. If anything goes wrong (i.e. ** OOM error), leave an error code in pParse and return NULL. @@ -215036,51 +216067,58 @@ static Fts5ExprNode *sqlite3Fts5ParseNode( if( eType!=FTS5_STRING && pLeft==0 ) return pRight; if( eType!=FTS5_STRING && pRight==0 ) return pLeft; - if( eType==FTS5_NOT ){ - nChild = 2; - }else if( eType==FTS5_AND || eType==FTS5_OR ){ - nChild = 2; - if( pLeft->eType==eType ) nChild += pLeft->nChild-1; - if( pRight->eType==eType ) nChild += pRight->nChild-1; - } + if( eType==FTS5_STRING + && pParse->bPhraseToAnd + && pNear->apPhrase[0]->nTerm>1 + ){ + pRet = fts5ParsePhraseToAnd(pParse, pNear); + }else{ + if( eType==FTS5_NOT ){ + nChild = 2; + }else if( eType==FTS5_AND || eType==FTS5_OR ){ + nChild = 2; + if( pLeft->eType==eType ) nChild += pLeft->nChild-1; + if( pRight->eType==eType ) nChild += pRight->nChild-1; + } - nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); - pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); + nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1); + pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte); - if( pRet ){ - pRet->eType = eType; - pRet->pNear = pNear; - fts5ExprAssignXNext(pRet); - if( eType==FTS5_STRING ){ - int iPhrase; - for(iPhrase=0; iPhrasenPhrase; iPhrase++){ - pNear->apPhrase[iPhrase]->pNode = pRet; - if( pNear->apPhrase[iPhrase]->nTerm==0 ){ - pRet->xNext = 0; - pRet->eType = FTS5_EOF; + if( pRet ){ + pRet->eType = eType; + pRet->pNear = pNear; + fts5ExprAssignXNext(pRet); + if( eType==FTS5_STRING ){ + int iPhrase; + for(iPhrase=0; iPhrasenPhrase; iPhrase++){ + pNear->apPhrase[iPhrase]->pNode = pRet; + if( pNear->apPhrase[iPhrase]->nTerm==0 ){ + pRet->xNext = 0; + pRet->eType = FTS5_EOF; + } } - } - if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){ - Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; - if( pNear->nPhrase!=1 - || pPhrase->nTerm>1 - || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst) - ){ - assert( pParse->rc==SQLITE_OK ); - pParse->rc = SQLITE_ERROR; - assert( pParse->zErr==0 ); - pParse->zErr = sqlite3_mprintf( - "fts5: %s queries are not supported (detail!=full)", - pNear->nPhrase==1 ? "phrase": "NEAR" - ); - sqlite3_free(pRet); - pRet = 0; + if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; + if( pNear->nPhrase!=1 + || pPhrase->nTerm>1 + || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst) + ){ + assert( pParse->rc==SQLITE_OK ); + pParse->rc = SQLITE_ERROR; + assert( pParse->zErr==0 ); + pParse->zErr = sqlite3_mprintf( + "fts5: %s queries are not supported (detail!=full)", + pNear->nPhrase==1 ? "phrase": "NEAR" + ); + sqlite3_free(pRet); + pRet = 0; + } } + }else{ + fts5ExprAddChildren(pRet, pLeft); + fts5ExprAddChildren(pRet, pRight); } - }else{ - fts5ExprAddChildren(pRet, pLeft); - fts5ExprAddChildren(pRet, pRight); } } } @@ -215301,8 +216339,17 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){ int iTerm; if( pNear->pColset ){ - int iCol = pNear->pColset->aiCol[0]; - zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]); + int ii; + Fts5Colset *pColset = pNear->pColset; + if( pColset->nCol>1 ) zRet = fts5PrintfAppend(zRet, "{"); + for(ii=0; iinCol; ii++){ + zRet = fts5PrintfAppend(zRet, "%s%s", + pConfig->azCol[pColset->aiCol[ii]], ii==pColset->nCol-1 ? "" : " " + ); + } + if( zRet ){ + zRet = fts5PrintfAppend(zRet, "%s : ", pColset->nCol>1 ? "}" : ""); + } if( zRet==0 ) return 0; } @@ -215425,7 +216472,7 @@ static void fts5ExprFunction( rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr); if( rc==SQLITE_OK ){ - rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr); + rc = sqlite3Fts5ExprNew(pConfig, 0, pConfig->nCol, zExpr, &pExpr, &zErr); } if( rc==SQLITE_OK ){ char *zText; @@ -216098,7 +217145,6 @@ static int sqlite3Fts5HashWrite( p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); } - nIncr += p->nData; }else{ /* Appending to an existing hash-entry. Check that there is enough @@ -216131,8 +217177,9 @@ static int sqlite3Fts5HashWrite( /* If this is a new rowid, append the 4-byte size field for the previous ** entry, and the new rowid for this entry. */ if( iRowid!=p->iRowid ){ + u64 iDiff = (u64)iRowid - (u64)p->iRowid; fts5HashAddPoslistSize(pHash, p, 0); - p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); + p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iDiff); p->iRowid = iRowid; bNew = 1; p->iSzPoslist = p->nData; @@ -218107,7 +219154,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ ASSERT_SZLEAF_OK(pIter->pLeaf); while( 1 ){ - i64 iDelta = 0; + u64 iDelta = 0; if( eDetail==FTS5_DETAIL_NONE ){ /* todo */ @@ -218122,7 +219169,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ i += nPos; } if( i>=n ) break; - i += fts5GetVarint(&a[i], (u64*)&iDelta); + i += fts5GetVarint(&a[i], &iDelta); pIter->iRowid += iDelta; /* If necessary, grow the pIter->aRowidOffset[] array. */ @@ -218221,7 +219268,7 @@ static void fts5SegIterNext_Reverse( if( pIter->iRowidOffset>0 ){ u8 *a = pIter->pLeaf->p; int iOff; - i64 iDelta; + u64 iDelta; pIter->iRowidOffset--; pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset]; @@ -218230,7 +219277,7 @@ static void fts5SegIterNext_Reverse( if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){ iOff += pIter->nPos; } - fts5GetVarint(&a[iOff], (u64*)&iDelta); + fts5GetVarint(&a[iOff], &iDelta); pIter->iRowid -= iDelta; }else{ fts5SegIterReverseNewPage(p, pIter); @@ -221350,7 +222397,9 @@ static void fts5MergePrefixLists( ** at most 20 bytes of unexpected space. */ fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); fts5BufferZero(&tmp); - sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist + 10 + 10); + sqlite3Fts5BufferSize(&p->rc, &tmp, + i1.nPoslist + i2.nPoslist + 10 + 10 + FTS5_DATA_ZERO_PADDING + ); if( p->rc ) break; sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); @@ -221424,9 +222473,10 @@ static void fts5MergePrefixLists( } assert_nc( out.n<=(p1->n+p2->n+9) ); - fts5BufferSet(&p->rc, p1, out.n, out.p); + fts5BufferFree(p1); fts5BufferFree(&tmp); - fts5BufferFree(&out); + memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING); + *p1 = out; } } @@ -222412,7 +223462,7 @@ static void fts5IndexIntegrityCheckSegment( ** error, or some other SQLite error code if another error (e.g. OOM) ** occurs. */ -static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ +static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){ int eDetail = p->pConfig->eDetail; u64 cksum2 = 0; /* Checksum based on contents of indexes */ Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */ @@ -222473,6 +223523,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ }else{ poslist.n = 0; fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist); + fts5BufferAppendBlob(&p->rc, &poslist, 4, (const u8*)"\0\0\0\0"); while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){ int iCol = FTS5_POS2COLUMN(iPos); int iTokOff = FTS5_POS2OFFSET(iPos); @@ -222483,7 +223534,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){ fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); fts5MultiIterFree(pIter); - if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; + if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; fts5StructureRelease(pStruct); #ifdef SQLITE_DEBUG @@ -223447,6 +224498,23 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){ #endif } +static int fts5UsePatternMatch( + Fts5Config *pConfig, + struct sqlite3_index_constraint *p +){ + assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB ); + assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE ); + if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){ + return 1; + } + if( pConfig->ePattern==FTS5_PATTERN_LIKE + && (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB) + ){ + return 1; + } + return 0; +} + /* ** Implementation of the xBestIndex method for FTS5 tables. Within the ** WHERE constraint, it searches for the following: @@ -223476,7 +224544,9 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){ ** ** Match against table column: "m" ** Match against rank column: "r" -** Match against other column: "" +** Match against other column: "M" +** LIKE against other column: "L" +** GLOB against other column: "G" ** Equality constraint against the rowid: "=" ** A < or <= against the rowid: "<" ** A > or >= against the rowid: ">" @@ -223537,7 +224607,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ return SQLITE_ERROR; } - idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 6 + 1); + idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1); if( idxStr==0 ) return SQLITE_NOMEM; pInfo->idxStr = idxStr; pInfo->needToFreeIdxStr = 1; @@ -223561,25 +224631,29 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ if( bSeenRank ) continue; idxStr[iIdxStr++] = 'r'; bSeenRank = 1; - }else{ + }else if( iCol>=0 ){ bSeenMatch = 1; - idxStr[iIdxStr++] = 'm'; - if( iColaConstraintUsage[i].argvIndex = ++iCons; pInfo->aConstraintUsage[i].omit = 1; } - } - else if( p->usable && bSeenEq==0 - && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 - ){ - idxStr[iIdxStr++] = '='; - bSeenEq = 1; - pInfo->aConstraintUsage[i].argvIndex = ++iCons; + }else if( p->usable ){ + if( iCol>=0 && iColop==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB ); + idxStr[iIdxStr++] = p->op==FTS5_PATTERN_LIKE ? 'L' : 'G'; + sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); + idxStr += strlen(&idxStr[iIdxStr]); + pInfo->aConstraintUsage[i].argvIndex = ++iCons; + assert( idxStr[iIdxStr]=='\0' ); + }else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){ + idxStr[iIdxStr++] = '='; + bSeenEq = 1; + pInfo->aConstraintUsage[i].argvIndex = ++iCons; + } } } @@ -224212,19 +225286,14 @@ static int fts5FilterMethod( case 'r': pRank = apVal[i]; break; - case 'm': { + case 'M': { const char *zText = (const char*)sqlite3_value_text(apVal[i]); if( zText==0 ) zText = ""; - - if( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ){ - iCol = 0; - do{ - iCol = iCol*10 + (idxStr[iIdxStr]-'0'); - iIdxStr++; - }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ); - }else{ - iCol = pConfig->nCol; - } + iCol = 0; + do{ + iCol = iCol*10 + (idxStr[iIdxStr]-'0'); + iIdxStr++; + }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ); if( zText[0]=='*' ){ /* The user has issued a query of the form "MATCH '*...'". This @@ -224234,7 +225303,7 @@ static int fts5FilterMethod( goto filter_out; }else{ char **pzErr = &pTab->p.base.zErrMsg; - rc = sqlite3Fts5ExprNew(pConfig, iCol, zText, &pExpr, pzErr); + rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr); pExpr = 0; @@ -224244,6 +225313,25 @@ static int fts5FilterMethod( break; } + case 'L': + case 'G': { + int bGlob = (idxStr[iIdxStr-1]=='G'); + const char *zText = (const char*)sqlite3_value_text(apVal[i]); + iCol = 0; + do{ + iCol = iCol*10 + (idxStr[iIdxStr]-'0'); + iIdxStr++; + }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ); + if( zText ){ + rc = sqlite3Fts5ExprPattern(pConfig, bGlob, iCol, zText, &pExpr); + } + if( rc==SQLITE_OK ){ + rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr); + pExpr = 0; + } + if( rc!=SQLITE_OK ) goto filter_out; + break; + } case '=': pRowidEq = apVal[i]; break; @@ -224491,7 +225579,8 @@ static int fts5SpecialInsert( int nMerge = sqlite3_value_int(pVal); rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge); }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){ - rc = sqlite3Fts5StorageIntegrity(pTab->pStorage); + int iArg = sqlite3_value_int(pVal); + rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, iArg); #ifdef SQLITE_DEBUG }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){ pConfig->bPrefixIndex = sqlite3_value_int(pVal); @@ -225654,8 +226743,7 @@ static int sqlite3Fts5GetTokenizer( Fts5Global *pGlobal, const char **azArg, int nArg, - Fts5Tokenizer **ppTok, - fts5_tokenizer **ppTokApi, + Fts5Config *pConfig, char **pzErr ){ Fts5TokenizerModule *pMod; @@ -225667,16 +226755,22 @@ static int sqlite3Fts5GetTokenizer( rc = SQLITE_ERROR; *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); }else{ - rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok); - *ppTokApi = &pMod->x; - if( rc!=SQLITE_OK && pzErr ){ - *pzErr = sqlite3_mprintf("error in tokenizer constructor"); + rc = pMod->x.xCreate( + pMod->pUserData, &azArg[1], (nArg?nArg-1:0), &pConfig->pTok + ); + pConfig->pTokApi = &pMod->x; + if( rc!=SQLITE_OK ){ + if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor"); + }else{ + pConfig->ePattern = sqlite3Fts5TokenizerPattern( + pMod->x.xCreate, pConfig->pTok + ); } } if( rc!=SQLITE_OK ){ - *ppTokApi = 0; - *ppTok = 0; + pConfig->pTokApi = 0; + pConfig->pTok = 0; } return rc; @@ -225725,7 +226819,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b", -1, SQLITE_TRANSIENT); } /* @@ -226288,9 +227382,16 @@ static int fts5StorageDeleteFromIndex( zText, nText, (void*)&ctx, fts5StorageInsertCallback ); p->aTotalSize[iCol-1] -= (i64)ctx.szCol; + if( p->aTotalSize[iCol-1]<0 ){ + rc = FTS5_CORRUPT; + } } } - p->nTotalRow--; + if( rc==SQLITE_OK && p->nTotalRow<1 ){ + rc = FTS5_CORRUPT; + }else{ + p->nTotalRow--; + } rc2 = sqlite3_reset(pSeek); if( rc==SQLITE_OK ) rc = rc2; @@ -226733,13 +227834,14 @@ static int fts5StorageIntegrityCallback( ** some other SQLite error code if an error occurs while attempting to ** determine this. */ -static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ +static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){ Fts5Config *pConfig = p->pConfig; - int rc; /* Return code */ + int rc = SQLITE_OK; /* Return code */ int *aColSize; /* Array of size pConfig->nCol */ i64 *aTotalSize; /* Array of size pConfig->nCol */ Fts5IntegrityCtx ctx; sqlite3_stmt *pScan; + int bUseCksum; memset(&ctx, 0, sizeof(Fts5IntegrityCtx)); ctx.pConfig = p->pConfig; @@ -226748,83 +227850,88 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){ aColSize = (int*)&aTotalSize[pConfig->nCol]; memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol); - /* Generate the expected index checksum based on the contents of the - ** %_content table. This block stores the checksum in ctx.cksum. */ - rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); - if( rc==SQLITE_OK ){ - int rc2; - while( SQLITE_ROW==sqlite3_step(pScan) ){ - int i; - ctx.iRowid = sqlite3_column_int64(pScan, 0); - ctx.szCol = 0; - if( pConfig->bColumnsize ){ - rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); - } - if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ - rc = sqlite3Fts5TermsetNew(&ctx.pTermset); - } - for(i=0; rc==SQLITE_OK && inCol; i++){ - if( pConfig->abUnindexed[i] ) continue; - ctx.iCol = i; + bUseCksum = (pConfig->eContent==FTS5_CONTENT_NORMAL + || (pConfig->eContent==FTS5_CONTENT_EXTERNAL && iArg) + ); + if( bUseCksum ){ + /* Generate the expected index checksum based on the contents of the + ** %_content table. This block stores the checksum in ctx.cksum. */ + rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0); + if( rc==SQLITE_OK ){ + int rc2; + while( SQLITE_ROW==sqlite3_step(pScan) ){ + int i; + ctx.iRowid = sqlite3_column_int64(pScan, 0); ctx.szCol = 0; - if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ - rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + if( pConfig->bColumnsize ){ + rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize); } - if( rc==SQLITE_OK ){ - const char *zText = (const char*)sqlite3_column_text(pScan, i+1); - int nText = sqlite3_column_bytes(pScan, i+1); - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, - zText, nText, - (void*)&ctx, - fts5StorageIntegrityCallback - ); - } - if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ - rc = FTS5_CORRUPT; + if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); } - aTotalSize[i] += ctx.szCol; - if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ - sqlite3Fts5TermsetFree(ctx.pTermset); - ctx.pTermset = 0; + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( pConfig->abUnindexed[i] ) continue; + ctx.iCol = i; + ctx.szCol = 0; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + rc = sqlite3Fts5TermsetNew(&ctx.pTermset); + } + if( rc==SQLITE_OK ){ + const char *zText = (const char*)sqlite3_column_text(pScan, i+1); + int nText = sqlite3_column_bytes(pScan, i+1); + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, + zText, nText, + (void*)&ctx, + fts5StorageIntegrityCallback + ); + } + if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ + rc = FTS5_CORRUPT; + } + aTotalSize[i] += ctx.szCol; + if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; + } } - } - sqlite3Fts5TermsetFree(ctx.pTermset); - ctx.pTermset = 0; + sqlite3Fts5TermsetFree(ctx.pTermset); + ctx.pTermset = 0; - if( rc!=SQLITE_OK ) break; + if( rc!=SQLITE_OK ) break; + } + rc2 = sqlite3_reset(pScan); + if( rc==SQLITE_OK ) rc = rc2; } - rc2 = sqlite3_reset(pScan); - if( rc==SQLITE_OK ) rc = rc2; - } - /* Test that the "totals" (sometimes called "averages") record looks Ok */ - if( rc==SQLITE_OK ){ - int i; - rc = fts5StorageLoadTotals(p, 0); - for(i=0; rc==SQLITE_OK && inCol; i++){ - if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT; + /* Test that the "totals" (sometimes called "averages") record looks Ok */ + if( rc==SQLITE_OK ){ + int i; + rc = fts5StorageLoadTotals(p, 0); + for(i=0; rc==SQLITE_OK && inCol; i++){ + if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT; + } } - } - /* Check that the %_docsize and %_content tables contain the expected - ** number of rows. */ - if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ - i64 nRow = 0; - rc = fts5StorageCount(p, "content", &nRow); - if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; - } - if( rc==SQLITE_OK && pConfig->bColumnsize ){ - i64 nRow = 0; - rc = fts5StorageCount(p, "docsize", &nRow); - if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + /* Check that the %_docsize and %_content tables contain the expected + ** number of rows. */ + if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ + i64 nRow = 0; + rc = fts5StorageCount(p, "content", &nRow); + if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + } + if( rc==SQLITE_OK && pConfig->bColumnsize ){ + i64 nRow = 0; + rc = fts5StorageCount(p, "docsize", &nRow); + if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT; + } } /* Pass the expected checksum down to the FTS index module. It will ** verify, amongst other things, that it matches the checksum generated by ** inspecting the index itself. */ if( rc==SQLITE_OK ){ - rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum); + rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum, bUseCksum); } sqlite3_free(aTotalSize); @@ -228266,6 +229373,133 @@ static int fts5PorterTokenize( ); } +/************************************************************************** +** Start of trigram implementation. +*/ +typedef struct TrigramTokenizer TrigramTokenizer; +struct TrigramTokenizer { + int bFold; /* True to fold to lower-case */ +}; + +/* +** Free a trigram tokenizer. +*/ +static void fts5TriDelete(Fts5Tokenizer *p){ + sqlite3_free(p); +} + +/* +** Allocate a trigram tokenizer. +*/ +static int fts5TriCreate( + void *pUnused, + const char **azArg, + int nArg, + Fts5Tokenizer **ppOut +){ + int rc = SQLITE_OK; + TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); + UNUSED_PARAM(pUnused); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + int i; + pNew->bFold = 1; + for(i=0; rc==SQLITE_OK && ibFold = (zArg[0]=='0'); + } + }else{ + rc = SQLITE_ERROR; + } + } + if( rc!=SQLITE_OK ){ + fts5TriDelete((Fts5Tokenizer*)pNew); + pNew = 0; + } + } + *ppOut = (Fts5Tokenizer*)pNew; + return rc; +} + +/* +** Trigram tokenizer tokenize routine. +*/ +static int fts5TriTokenize( + Fts5Tokenizer *pTok, + void *pCtx, + int unusedFlags, + const char *pText, int nText, + int (*xToken)(void*, int, const char*, int, int, int) +){ + TrigramTokenizer *p = (TrigramTokenizer*)pTok; + int rc = SQLITE_OK; + char aBuf[32]; + const unsigned char *zIn = (const unsigned char*)pText; + const unsigned char *zEof = &zIn[nText]; + u32 iCode; + + UNUSED_PARAM(unusedFlags); + while( 1 ){ + char *zOut = aBuf; + int iStart = zIn - (const unsigned char*)pText; + const unsigned char *zNext; + + READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) break; + zNext = zIn; + if( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); + READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) break; + }else{ + break; + } + if( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); + READ_UTF8(zIn, zEof, iCode); + if( iCode==0 ) break; + if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0); + WRITE_UTF8(zOut, iCode); + }else{ + break; + } + rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf); + if( rc!=SQLITE_OK ) break; + zIn = zNext; + } + + return rc; +} + +/* +** Argument xCreate is a pointer to a constructor function for a tokenizer. +** pTok is a tokenizer previously created using the same method. This function +** returns one of FTS5_PATTERN_NONE, FTS5_PATTERN_LIKE or FTS5_PATTERN_GLOB +** indicating the style of pattern matching that the tokenizer can support. +** In practice, this is: +** +** "trigram" tokenizer, case_sensitive=1 - FTS5_PATTERN_GLOB +** "trigram" tokenizer, case_sensitive=0 (the default) - FTS5_PATTERN_LIKE +** all other tokenizers - FTS5_PATTERN_NONE +*/ +static int sqlite3Fts5TokenizerPattern( + int (*xCreate)(void*, const char**, int, Fts5Tokenizer**), + Fts5Tokenizer *pTok +){ + if( xCreate==fts5TriCreate ){ + TrigramTokenizer *p = (TrigramTokenizer*)pTok; + return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB; + } + return FTS5_PATTERN_NONE; +} + /* ** Register all built-in tokenizers with FTS5. */ @@ -228277,6 +229511,7 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){ { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}}, { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }}, { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }}, + { "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}}, }; int rc = SQLITE_OK; /* Return code */ @@ -229069,8 +230304,10 @@ static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ } iTbl++; } + aAscii[0] = 0; /* 0x00 is never a token character */ } + /* ** 2015 May 30 ** @@ -230508,9 +231745,9 @@ SQLITE_API int sqlite3_stmt_init( #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ /************** End of stmt.c ************************************************/ -#if __LINE__!=230511 +#if __LINE__!=231748 #undef SQLITE_SOURCE_ID -#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0alt2" +#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089falt2" #endif /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } diff --git a/TMessagesProj/jni/sqlite/sqlite3.h b/TMessagesProj/jni/sqlite/sqlite3.h index 910b687aa7d..9098a372970 100644 --- a/TMessagesProj/jni/sqlite/sqlite3.h +++ b/TMessagesProj/jni/sqlite/sqlite3.h @@ -123,9 +123,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.33.0" -#define SQLITE_VERSION_NUMBER 3033000 -#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f" +#define SQLITE_VERSION "3.34.0" +#define SQLITE_VERSION_NUMBER 3034000 +#define SQLITE_SOURCE_ID "2020-12-01 16:14:00 a26b6597e3ae272231b96f9982c3bcc17ddec2f2b6eb4df06a224b91089fed5b" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -504,6 +504,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) +#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) @@ -6186,6 +6187,57 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); */ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); +/* +** CAPI3REF: Determine the transaction state of a database +** METHOD: sqlite3 +** +** ^The sqlite3_txn_state(D,S) interface returns the current +** [transaction state] of schema S in database connection D. ^If S is NULL, +** then the highest transaction state of any schema on database connection D +** is returned. Transaction states are (in order of lowest to highest): +**
    +**
  1. SQLITE_TXN_NONE +**
  2. SQLITE_TXN_READ +**
  3. SQLITE_TXN_WRITE +**
+** ^If the S argument to sqlite3_txn_state(D,S) is not the name of +** a valid schema, then -1 is returned. +*/ +SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema); + +/* +** CAPI3REF: Allowed return values from [sqlite3_txn_state()] +** KEYWORDS: {transaction state} +** +** These constants define the current transaction state of a database file. +** ^The [sqlite3_txn_state(D,S)] interface returns one of these +** constants in order to describe the transaction state of schema S +** in [database connection] D. +** +**
+** [[SQLITE_TXN_NONE]]
SQLITE_TXN_NONE
+**
The SQLITE_TXN_NONE state means that no transaction is currently +** pending.
+** +** [[SQLITE_TXN_READ]]
SQLITE_TXN_READ
+**
The SQLITE_TXN_READ state means that the database is currently +** in a read transaction. Content has been read from the database file +** but nothing in the database file has changed. The transaction state +** will advanced to SQLITE_TXN_WRITE if any changes occur and there are +** no other conflicting concurrent write transactions. The transaction +** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or +** [COMMIT].
+** +** [[SQLITE_TXN_WRITE]]
SQLITE_TXN_WRITE
+**
The SQLITE_TXN_WRITE state means that the database is currently +** in a write transaction. Content has been written to the database file +** but has not yet committed. The transaction state will change to +** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
+*/ +#define SQLITE_TXN_NONE 0 +#define SQLITE_TXN_READ 1 +#define SQLITE_TXN_WRITE 2 + /* ** CAPI3REF: Find the next prepared statement ** METHOD: sqlite3 @@ -7712,7 +7764,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_RESULT_INTREAL 27 #define SQLITE_TESTCTRL_PRNG_SEED 28 #define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29 -#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_SEEK_COUNT 30 +#define SQLITE_TESTCTRL_LAST 30 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -9192,10 +9245,11 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE ** ** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn] -** method of a [virtual table], then it returns true if and only if the +** method of a [virtual table], then it might return true if the ** column is being fetched as part of an UPDATE operation during which the -** column value will not change. Applications might use this to substitute -** a return value that is less expensive to compute and that the corresponding +** column value will not change. The virtual table implementation can use +** this hint as permission to substitute a return value that is less +** expensive to compute and that the corresponding ** [xUpdate] method understands as a "no-change" value. ** ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that @@ -9204,6 +9258,12 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces]. ** In that case, [sqlite3_value_nochange(X)] will return true for the ** same column in the [xUpdate] method. +** +** The sqlite3_vtab_nochange() routine is an optimization. Virtual table +** implementations should continue to give a correct answer even if the +** sqlite3_vtab_nochange() interface were to always return false. In the +** current implementation, the sqlite3_vtab_nochange() interface does always +** returns false for the enhanced [UPDATE FROM] statement. */ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*); @@ -9345,6 +9405,7 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction +** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the ** [sqlite3_db_cacheflush(D)] interface invoked, any dirty @@ -9377,6 +9438,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); /* ** CAPI3REF: The pre-update hook. +** METHOD: sqlite3 ** ** ^These interfaces are only available if SQLite is compiled using the ** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. @@ -9417,7 +9479,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); ** seventh parameter is the final rowid value of the row being inserted ** or updated. The value of the seventh parameter passed to the callback ** function is not defined for operations on WITHOUT ROWID tables, or for -** INSERT operations on rowid tables. +** DELETE operations on rowid tables. ** ** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()], ** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces @@ -9479,6 +9541,7 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); /* ** CAPI3REF: Low-level system error code +** METHOD: sqlite3 ** ** ^Attempt to return the underlying operating system error code or error ** number that caused the most recent I/O error or failure to open a file. diff --git a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp index b1e6485fbd3..f68cc0450b8 100644 --- a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp +++ b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp @@ -73,7 +73,6 @@ class JavaObject { struct InstanceHolder { std::unique_ptr nativeInstance; std::unique_ptr groupNativeInstance; - jobject javaInstance; std::shared_ptr _videoCapture; std::shared_ptr _platformContext; }; @@ -254,17 +253,17 @@ void initWebRTC(JNIEnv *env) { JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeGroupNativeInstance(JNIEnv *env, jclass clazz, jobject instanceObj, jboolean highQuality) { initWebRTC(env); - jobject globalRef = env->NewGlobalRef(instanceObj); - std::shared_ptr platformContext = std::make_shared(env); + std::shared_ptr platformContext = std::make_shared(env, instanceObj); GroupInstanceDescriptor descriptor = { - .networkStateUpdated = [globalRef](bool state) { - tgvoip::jni::DoWithJNI([globalRef, state](JNIEnv *env) { + .networkStateUpdated = [platformContext](bool state) { + tgvoip::jni::DoWithJNI([platformContext, state](JNIEnv *env) { + jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance(); env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onNetworkStateUpdated", "(Z)V"), state); }); }, - .audioLevelsUpdated = [globalRef](GroupLevelsUpdate const &update) { - tgvoip::jni::DoWithJNI([globalRef, update](JNIEnv *env) { + .audioLevelsUpdated = [platformContext](GroupLevelsUpdate const &update) { + tgvoip::jni::DoWithJNI([platformContext, update](JNIEnv *env) { unsigned int size = update.updates.size(); jintArray intArray = env->NewIntArray(size); jfloatArray floatArray = env->NewFloatArray(size); @@ -282,6 +281,7 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeGrou env->SetFloatArrayRegion(floatArray, 0, size, floatFill); env->SetBooleanArrayRegion(boolArray, 0, size, boolFill); + jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance(); env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onAudioLevelsUpdated", "([I[F[Z)V"), intArray, floatArray, boolArray); env->DeleteLocalRef(intArray); env->DeleteLocalRef(floatArray); @@ -293,14 +293,14 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeGrou auto *holder = new InstanceHolder; holder->groupNativeInstance = std::make_unique(std::move(descriptor)); - holder->javaInstance = globalRef; holder->_platformContext = platformContext; - holder->groupNativeInstance->emitJoinPayload([globalRef](const GroupJoinPayload& payload) { + holder->groupNativeInstance->emitJoinPayload([platformContext](const GroupJoinPayload& payload) { JNIEnv *env = webrtc::AttachCurrentThreadIfNeeded(); jobjectArray array = env->NewObjectArray(payload.fingerprints.size(), FingerprintClass, 0); for (int a = 0; a < payload.fingerprints.size(); a++) { env->SetObjectArrayElement(array, a, asJavaFingerprint(env, payload.fingerprints[a].hash, payload.fingerprints[a].setup, payload.fingerprints[a].fingerprint)); } + jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance(); env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onEmitJoinPayload", "(Ljava/lang/String;Ljava/lang/String;[Lorg/telegram/messenger/voip/Instance$Fingerprint;I)V"), env->NewStringUTF(payload.ufrag.c_str()), env->NewStringUTF(payload.pwd.c_str()), array, (jint) payload.ssrc); }); return reinterpret_cast(holder); @@ -382,10 +382,15 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeNati memcpy(encryptionKeyValue->data(), valueBytes, 256); env->ReleaseByteArrayElements(valueByteArray, (jbyte *) valueBytes, JNI_ABORT); - jobject globalRef = env->NewGlobalRef(instanceObj); std::shared_ptr videoCapture = videoCapturer ? std::shared_ptr(reinterpret_cast(videoCapturer)) : nullptr; - std::shared_ptr platformContext = videoCapture ? videoCapture->getPlatformContext() : std::make_shared(env); + std::shared_ptr platformContext; + if (videoCapture) { + platformContext = videoCapture->getPlatformContext(); + ((AndroidContext *) platformContext.get())->setJavaInstance(env, instanceObj); + } else { + platformContext = std::make_shared(env, instanceObj); + } Descriptor descriptor = { .config = Config{ @@ -393,45 +398,49 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeNati .receiveTimeout = configObject.getDoubleField("receiveTimeout"), .dataSaving = parseDataSaving(env, configObject.getIntField("dataSaving")), .enableP2P = configObject.getBooleanField("enableP2p") == JNI_TRUE, + .enableStunMarking = configObject.getBooleanField("enableSm") == JNI_TRUE, .enableAEC = configObject.getBooleanField("enableAec") == JNI_TRUE, .enableNS = configObject.getBooleanField("enableNs") == JNI_TRUE, .enableAGC = configObject.getBooleanField("enableAgc") == JNI_TRUE, - .enableStunMarking = configObject.getBooleanField("enableSm") == JNI_TRUE, .enableVolumeControl = true, .logPath = tgvoip::jni::JavaStringToStdString(env, configObject.getStringField("logPath")), + .statsLogPath = tgvoip::jni::JavaStringToStdString(env, configObject.getStringField("statsLogPath")), .maxApiLayer = configObject.getIntField("maxApiLayer"), .enableHighBitrateVideo = true, - .statsLogPath = tgvoip::jni::JavaStringToStdString(env, configObject.getStringField("statsLogPath")), .preferredVideoCodecs = {cricket::kVp9CodecName} }, .encryptionKey = EncryptionKey( std::move(encryptionKeyValue), encryptionKeyObject.getBooleanField("isOutgoing") == JNI_TRUE), .videoCapture = videoCapture, - .stateUpdated = [globalRef](State state) { + .stateUpdated = [platformContext](State state) { jint javaState = asJavaState(state); + jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance(); tgvoip::jni::DoWithJNI([globalRef, javaState](JNIEnv *env) { env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onStateUpdated", "(I)V"), javaState); }); }, - .platformContext = platformContext, - .signalBarsUpdated = [globalRef](int count) { + .signalBarsUpdated = [platformContext](int count) { + jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance(); tgvoip::jni::DoWithJNI([globalRef, count](JNIEnv *env) { env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onSignalBarsUpdated", "(I)V"), count); }); }, - .remoteMediaStateUpdated = [globalRef](AudioState audioState, VideoState videoState) { + .remoteMediaStateUpdated = [platformContext](AudioState audioState, VideoState videoState) { + jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance(); tgvoip::jni::DoWithJNI([globalRef, audioState, videoState](JNIEnv *env) { env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onRemoteMediaStateUpdated", "(II)V"), (jint) audioState, (jint )videoState); }); }, - .signalingDataEmitted = [globalRef](const std::vector &data) { + .signalingDataEmitted = [platformContext](const std::vector &data) { + jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance(); tgvoip::jni::DoWithJNI([globalRef, data](JNIEnv *env) { jbyteArray arr = copyVectorToJavaByteArray(env, data); env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onSignalingData", "([B)V"), arr); env->DeleteLocalRef(arr); }); }, + .platformContext = platformContext, }; for (int i = 0, size = env->GetArrayLength(endpoints); i < size; i++) { @@ -474,7 +483,6 @@ JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeNati auto *holder = new InstanceHolder; holder->nativeInstance = tgcalls::Meta::Create(v, std::move(descriptor)); - holder->javaInstance = globalRef; holder->_videoCapture = videoCapture; holder->_platformContext = platformContext; holder->nativeInstance->setIncomingVideoOutput(webrtc::JavaToNativeVideoSink(env, remoteSink)); @@ -576,10 +584,10 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_stopNativ } instance->nativeInstance->stop([instance](FinalState finalState) { JNIEnv *env = webrtc::AttachCurrentThreadIfNeeded(); - const std::string &path = tgvoip::jni::JavaStringToStdString(env, JavaObject(env, instance->javaInstance).getStringField("persistentStateFilePath")); + jobject globalRef = ((AndroidContext *) instance->_platformContext.get())->getJavaInstance(); + const std::string &path = tgvoip::jni::JavaStringToStdString(env, JavaObject(env, globalRef).getStringField("persistentStateFilePath")); savePersistentState(path.c_str(), finalState.persistentState); - env->CallVoidMethod(instance->javaInstance, env->GetMethodID(NativeInstanceClass, "onStop", "(Lorg/telegram/messenger/voip/Instance$FinalState;)V"), asJavaFinalState(env, finalState)); - env->DeleteGlobalRef(instance->javaInstance); + env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onStop", "(Lorg/telegram/messenger/voip/Instance$FinalState;)V"), asJavaFinalState(env, finalState)); delete instance; }); } @@ -591,13 +599,12 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_stopGroup } instance->groupNativeInstance->stop(); instance->groupNativeInstance.reset(); - env->DeleteGlobalRef(instance->javaInstance); delete instance; } JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_createVideoCapturer(JNIEnv *env, jclass clazz, jobject localSink, jboolean front) { initWebRTC(env); - std::unique_ptr capture = tgcalls::VideoCaptureInterface::Create(front ? "front" : "back", std::make_shared(env)); + std::unique_ptr capture = tgcalls::VideoCaptureInterface::Create(front ? "front" : "back", std::make_shared(env, nullptr)); capture->setOutput(webrtc::JavaToNativeVideoSink(env, localSink)); capture->setState(VideoState::Active); return reinterpret_cast(capture.release()); diff --git a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidContext.cpp b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidContext.cpp index 9a8e6b41a19..e49d1ce9fde 100644 --- a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidContext.cpp +++ b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidContext.cpp @@ -1,13 +1,15 @@ +#include #include "AndroidContext.h" #include "sdk/android/native_api/jni/jvm.h" namespace tgcalls { -AndroidContext::AndroidContext(JNIEnv *env) { +AndroidContext::AndroidContext(JNIEnv *env, jobject instance) { VideoCameraCapturerClass = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/messenger/voip/VideoCameraCapturer")); jmethodID initMethodId = env->GetMethodID(VideoCameraCapturerClass, "", "()V"); javaCapturer = env->NewGlobalRef(env->NewObject(VideoCameraCapturerClass, initMethodId)); + javaInstance = env->NewGlobalRef(instance); } AndroidContext::~AndroidContext() { @@ -19,6 +21,18 @@ AndroidContext::~AndroidContext() { javaCapturer = nullptr; env->DeleteGlobalRef(VideoCameraCapturerClass); + + if (javaInstance) { + env->DeleteGlobalRef(javaInstance); + } +} + +void AndroidContext::setJavaInstance(JNIEnv *env, jobject instance) { + javaInstance = env->NewGlobalRef(instance); +} + +jobject AndroidContext::getJavaInstance() { + return javaInstance; } jobject AndroidContext::getJavaCapturer() { diff --git a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidContext.h b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidContext.h index 5ee1bf8be80..da60b8771ba 100644 --- a/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidContext.h +++ b/TMessagesProj/jni/voip/tgcalls/platform/android/AndroidContext.h @@ -9,15 +9,19 @@ namespace tgcalls { class AndroidContext final : public PlatformContext { public: - AndroidContext(JNIEnv *env); + AndroidContext(JNIEnv *env, jobject instance); ~AndroidContext() override; jobject getJavaCapturer(); + jobject getJavaInstance(); jclass getJavaCapturerClass(); + void setJavaInstance(JNIEnv *env, jobject instance); + private: jclass VideoCameraCapturerClass = nullptr; jobject javaCapturer = nullptr; + jobject javaInstance = nullptr; }; diff --git a/TMessagesProj/jni/voip/webrtc/api/video/i420_buffer.cc b/TMessagesProj/jni/voip/webrtc/api/video/i420_buffer.cc index 2a52217ce34..312a7cf0c94 100644 --- a/TMessagesProj/jni/voip/webrtc/api/video/i420_buffer.cc +++ b/TMessagesProj/jni/voip/webrtc/api/video/i420_buffer.cc @@ -118,13 +118,12 @@ rtc::scoped_refptr I420Buffer::Rotate( rtc::scoped_refptr buffer = I420Buffer::Create(rotated_width, rotated_height); - RTC_CHECK_EQ(0, - libyuv::I420Rotate( - src.DataY(), src.StrideY(), src.DataU(), src.StrideU(), - src.DataV(), src.StrideV(), buffer->MutableDataY(), - buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(), - buffer->MutableDataV(), buffer->StrideV(), src.width(), - src.height(), static_cast(rotation))); + libyuv::I420Rotate( + src.DataY(), src.StrideY(), src.DataU(), src.StrideU(), + src.DataV(), src.StrideV(), buffer->MutableDataY(), + buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(), + buffer->MutableDataV(), buffer->StrideV(), src.width(), + src.height(), static_cast(rotation)); return buffer; } diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java index a317fdb1559..e53d29aa1ce 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChatListItemAnimator.java @@ -616,7 +616,7 @@ protected void animateMoveImpl(RecyclerView.ViewHolder holder, MoveInfo moveInfo if (holder.itemView instanceof BotHelpCell) { BotHelpCell botCell = (BotHelpCell) holder.itemView ; - int top = recyclerListView.getMeasuredHeight() / 2 - botCell.getMeasuredHeight() / 2 + activity.getChatListViewPadding(); + float top = recyclerListView.getMeasuredHeight() / 2 - botCell.getMeasuredHeight() / 2 + activity.getChatListViewPadding(); float animateTo = 0; if (botCell.getTop() > top) { animateTo = top - botCell.getTop(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 71b5e4de551..7b4a25faa8c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -18,7 +18,7 @@ public class BuildVars { public static boolean LOGS_ENABLED = false; public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; - public static int BUILD_VERSION = 2195; + public static int BUILD_VERSION = 2196; public static String BUILD_VERSION_STRING = "7.3.0"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index 4a18dab2605..816e8ef1751 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -3233,7 +3233,7 @@ private static TLRPC.PhotoSize scaleAndSaveImageInternal(TLRPC.PhotoSize photoSi fileDir = location.volume_id != Integer.MIN_VALUE ? FileLoader.getDirectory(FileLoader.MEDIA_DIR_IMAGE) : FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE); } final File cacheFile = new File(fileDir, fileName); - if (compressFormat == Bitmap.CompressFormat.JPEG && progressive) { + if (compressFormat == Bitmap.CompressFormat.JPEG && progressive && BuildVars.DEBUG_VERSION) { photoSize.size = Utilities.saveProgressiveJpeg(scaledBitmap, scaledBitmap.getWidth(), scaledBitmap.getHeight(), scaledBitmap.getRowBytes(), quality, cacheFile.getAbsolutePath()); } else { FileOutputStream stream = new FileOutputStream(cacheFile); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index e98001998b5..4a5019f028d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -3948,6 +3948,7 @@ public void loadReplyMessagesForMessages(final ArrayList messages getMessagesStorage().getStorageQueue().postRunnable(() -> { try { + ArrayList loadedMessages = new ArrayList<>(); SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, m.date, r.random_id FROM randoms as r INNER JOIN messages as m ON r.mid = m.mid WHERE r.random_id IN(%s)", TextUtils.join(",", replyMessages))); while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); @@ -3964,6 +3965,7 @@ public void loadReplyMessagesForMessages(final ArrayList messages replyMessageRandomOwners.remove(value); if (arrayList != null) { MessageObject messageObject = new MessageObject(currentAccount, message, false, false); + loadedMessages.add(messageObject); for (int b = 0; b < arrayList.size(); b++) { MessageObject object = arrayList.get(b); object.replyMessageObject = messageObject; @@ -3985,7 +3987,7 @@ public void loadReplyMessagesForMessages(final ArrayList messages } } } - AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.replyMessagesDidLoad, dialogId)); + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.replyMessagesDidLoad, dialogId, loadedMessages)); if (callback != null) { callback.run(); } @@ -4207,7 +4209,7 @@ private void broadcastReplyMessages(ArrayList result, LongSparseA } } if (changed) { - getNotificationCenter().postNotificationName(NotificationCenter.replyMessagesDidLoad, dialog_id); + getNotificationCenter().postNotificationName(NotificationCenter.replyMessagesDidLoad, dialog_id, messageObjects); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index cc42a943438..f21b75caa88 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -13,7 +13,6 @@ import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; -import android.util.Log; import android.util.LongSparseArray; import android.util.Pair; import android.util.SparseArray; @@ -270,7 +269,7 @@ public void openDatabase(int openTries) { database.executeFast("PRAGMA secure_delete = ON").stepThis().dispose(); database.executeFast("PRAGMA temp_store = MEMORY").stepThis().dispose(); database.executeFast("PRAGMA journal_mode = WAL").stepThis().dispose(); - database.executeFast("PRAGMA journal_size_limit = 52428800").stepThis().dispose(); + database.executeFast("PRAGMA journal_size_limit = 10485760").stepThis().dispose(); if (createTable) { if (BuildVars.LOGS_ENABLED) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 66c73eb366e..68baa2e16f8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -9,6 +9,8 @@ package org.telegram.messenger; import androidx.annotation.UiThread; + +import android.os.SystemClock; import android.util.SparseArray; import java.util.ArrayList; @@ -203,7 +205,7 @@ public class NotificationCenter { public static final int closeSearchByActiveAction = totalEvents++; public static final int messagePlayingSpeedChanged = totalEvents++; public static final int screenStateChanged = totalEvents++; - public static final int didDatabaseCleared = totalEvents++; + public static final int didClearDatabase = totalEvents++; public static final int voipServiceCreated = totalEvents++; public static final int webRtcMicAmplitudeEvent = totalEvents++; public static final int webRtcSpeakerAmplitudeEvent = totalEvents++; @@ -217,6 +219,8 @@ public class NotificationCenter { private ArrayList delayedPostsTmp = new ArrayList<>(10); private ArrayList postponeCallbackList = new ArrayList<>(10); + private Runnable checkForExpiredNotifications; + private int broadcasting = 0; private int animationInProgressCount; @@ -224,7 +228,7 @@ public class NotificationCenter { HashSet heavyOperationsCounter = new HashSet<>(); - private final HashMap allowedNotifications = new HashMap<>(); + private final HashMap allowedNotifications = new HashMap<>(); public interface NotificationCenterDelegate { void didReceivedNotification(int id, int account, Object... args); @@ -294,27 +298,56 @@ public int setAnimationInProgress(int oldIndex, int[] allowedNotifications, bool if (stopHeavyOperations) { heavyOperationsCounter.add(animationInProgressPointer); } - if (allowedNotifications == null) { - allowedNotifications = new int[0]; + AllowedNotifications notifications = new AllowedNotifications(); + notifications.allowedIds = allowedNotifications; + this.allowedNotifications.put(animationInProgressPointer, notifications); + if (checkForExpiredNotifications == null) { + AndroidUtilities.runOnUIThread(checkForExpiredNotifications = this::checkForExpiredNotifications, 1017); } - this.allowedNotifications.put(animationInProgressPointer, allowedNotifications); - return animationInProgressPointer; } - public void updateAllowedNotifications(int transitionAnimationIndex, int[] allowedNotifications) { - if (this.allowedNotifications.containsKey(transitionAnimationIndex)) { - if (allowedNotifications == null) { - allowedNotifications = new int[0]; + private void checkForExpiredNotifications() { + checkForExpiredNotifications = null; + if (this.allowedNotifications.isEmpty()) { + return; + } + long minTime = Long.MAX_VALUE; + long currentTime = SystemClock.elapsedRealtime(); + ArrayList expiredIndices = null; + for (HashMap.Entry entry : this.allowedNotifications.entrySet()) { + AllowedNotifications allowedNotification = entry.getValue(); + if (currentTime - allowedNotification.time > 1000) { + if (expiredIndices == null) { + expiredIndices = new ArrayList<>(); + } + expiredIndices.add(entry.getKey()); + } else { + minTime = Math.min(allowedNotification.time, minTime); } - this.allowedNotifications.put(transitionAnimationIndex, allowedNotifications); + } + if (expiredIndices != null) { + for (int i = 0; i < expiredIndices.size(); i++) { + onAnimationFinish(expiredIndices.get(i)); + } + } + if (minTime != Long.MAX_VALUE) { + long time = 1017 - (currentTime - minTime); + AndroidUtilities.runOnUIThread(() -> checkForExpiredNotifications = this::checkForExpiredNotifications, Math.max(17, time)); } } - public void onAnimationFinish(int index) { - int[] notifications = allowedNotifications.remove(index); + public void updateAllowedNotifications(int transitionAnimationIndex, int[] allowedNotifications) { + AllowedNotifications notifications = this.allowedNotifications.get(transitionAnimationIndex); if (notifications != null) { + notifications.allowedIds = allowedNotifications; + } + } + + public void onAnimationFinish(int index) { + AllowedNotifications allowed = allowedNotifications.remove(index); + if (allowed != null) { animationInProgressCount--; if (!heavyOperationsCounter.isEmpty()) { heavyOperationsCounter.remove(index); @@ -326,6 +359,10 @@ public void onAnimationFinish(int index) { runDelayedNotifications(); } } + if (checkForExpiredNotifications != null && allowedNotifications.isEmpty()) { + AndroidUtilities.cancelRunOnUIThread(checkForExpiredNotifications); + checkForExpiredNotifications = null; + } } public void runDelayedNotifications() { @@ -361,11 +398,20 @@ public int getCurrentHeavyOperationFlags() { public void postNotificationName(int id, Object... args) { boolean allowDuringAnimation = id == startAllHeavyOperations || id == stopAllHeavyOperations || id == didReplacedPhotoInMemCache; + ArrayList expiredIndices = null; if (!allowDuringAnimation && !allowedNotifications.isEmpty()) { int size = allowedNotifications.size(); int allowedCount = 0; - for (Integer key : allowedNotifications.keySet()) { - int[] allowed = allowedNotifications.get(key); + long currentTime = SystemClock.elapsedRealtime(); + for (HashMap.Entry entry : allowedNotifications.entrySet()) { + AllowedNotifications allowedNotification = entry.getValue(); + if (currentTime - allowedNotification.time > 1000) { + if (expiredIndices == null) { + expiredIndices = new ArrayList<>(); + } + expiredIndices.add(entry.getKey()); + } + int[] allowed = allowedNotification.allowedIds; if (allowed != null) { for (int a = 0; a < allowed.length; a++) { if (allowed[a] == id) { @@ -387,6 +433,12 @@ public void postNotificationName(int id, Object... args) { currentHeavyOperationFlags |= flags; } postNotificationNameInternal(id, allowDuringAnimation, args); + + if (expiredIndices != null) { + for (int i = 0; i < expiredIndices.size(); i++) { + onAnimationFinish(expiredIndices.get(i)); + } + } } @UiThread @@ -528,4 +580,14 @@ public void doOnIdle(Runnable runnable) { runnable.run(); } } + + private static class AllowedNotifications { + + int[] allowedIds; + final long time; + + private AllowedNotifications() { + time = SystemClock.elapsedRealtime(); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index 8d9d04f7b27..b03a7b039d1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -2913,13 +2913,15 @@ private String validateChannelId(long dialogId, String name, long[] vibrationPat if (!settings.equals(newSettingsHash)) { SharedPreferences.Editor editor = null; if (channelImportance == NotificationManager.IMPORTANCE_NONE) { - if (isInApp) { - editor = preferences.edit(); - if (isDefault) { + editor = preferences.edit(); + if (isDefault) { + if (!isInApp) { editor.putInt(getGlobalNotificationsKey(type), Integer.MAX_VALUE); - } else { - editor.putInt("notify2_" + dialogId, 2); + updateServerNotificationsSettings(type); } + } else { + editor.putInt("notify2_" + dialogId, 2); + updateServerNotificationsSettings(dialogId, true); } edited = true; } else if (channelImportance != importance) { @@ -3063,7 +3065,7 @@ private String validateChannelId(long dialogId, String name, long[] vibrationPat if (edited && newSettingsHash != null) { preferences.edit().putString(key, channelId).putString(key + "_s", newSettingsHash).commit(); - } else { + } else if (!isInApp || !isDefault) { for (int a = 0; a < vibrationPattern.length; a++) { newSettings.append(vibrationPattern[a]); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsDisabledReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsDisabledReceiver.java index c8e31ec001d..0fa0e7e30ee 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsDisabledReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsDisabledReceiver.java @@ -23,7 +23,7 @@ public class NotificationsDisabledReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { String channelId = intent.getStringExtra(EXTRA_NOTIFICATION_CHANNEL_ID); boolean state = intent.getBooleanExtra(EXTRA_BLOCKED_STATE, false); - if (TextUtils.isEmpty(channelId)) { + if (TextUtils.isEmpty(channelId) || channelId.contains("_ia_")) { return; } String[] args = channelId.split("_"); @@ -38,11 +38,14 @@ public void onReceive(Context context, Intent intent) { SharedPreferences preferences = AccountInstance.getInstance(account).getNotificationsSettings(); SharedPreferences.Editor editor = preferences.edit(); if (args[1].startsWith("channel")) { - editor.putInt(NotificationsController.getGlobalNotificationsKey(NotificationsController.TYPE_CHANNEL), state ? Integer.MAX_VALUE : 0); + editor.putInt(NotificationsController.getGlobalNotificationsKey(NotificationsController.TYPE_CHANNEL), state ? Integer.MAX_VALUE : 0).commit(); + AccountInstance.getInstance(account).getNotificationsController().updateServerNotificationsSettings(NotificationsController.TYPE_CHANNEL); } else if (args[1].startsWith("groups")) { - editor.putInt(NotificationsController.getGlobalNotificationsKey(NotificationsController.TYPE_GROUP), state ? Integer.MAX_VALUE : 0); + editor.putInt(NotificationsController.getGlobalNotificationsKey(NotificationsController.TYPE_GROUP), state ? Integer.MAX_VALUE : 0).commit(); + AccountInstance.getInstance(account).getNotificationsController().updateServerNotificationsSettings(NotificationsController.TYPE_GROUP); } else if (args[1].startsWith("private")) { - editor.putInt(NotificationsController.getGlobalNotificationsKey(NotificationsController.TYPE_PRIVATE), state ? Integer.MAX_VALUE : 0); + editor.putInt(NotificationsController.getGlobalNotificationsKey(NotificationsController.TYPE_PRIVATE), state ? Integer.MAX_VALUE : 0).commit(); + AccountInstance.getInstance(account).getNotificationsController().updateServerNotificationsSettings(NotificationsController.TYPE_PRIVATE); } else { long dialogId = Utilities.parseLong(args[1]); if (dialogId == 0) { @@ -52,7 +55,9 @@ public void onReceive(Context context, Intent intent) { if (!state) { editor.remove("notifyuntil_" + dialogId); } + editor.commit(); + AccountInstance.getInstance(account).getNotificationsController().updateServerNotificationsSettings(dialogId, true); } - editor.commit(); + AccountInstance.getInstance(account).getConnectionsManager().resumeNetworkMaybe(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java index 604239ef18a..03f1bf03928 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java @@ -23,6 +23,7 @@ package org.telegram.messenger; import android.graphics.Bitmap; +import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; @@ -37,6 +38,7 @@ import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.SystemClock; import org.telegram.ui.ActionBar.Theme; @@ -103,7 +105,9 @@ public static class SvgDrawable extends Drawable { private int height; private static int[] parentPosition = new int[2]; - private LinearGradient backgroundGradient; + private Shader backgroundGradient; + private Bitmap backgroundBitmap; + private Canvas backgroundCanvas; private LinearGradient placeholderGradient; private Matrix placeholderMatrix; private static float totalTranslation; @@ -233,7 +237,16 @@ public void setupGradient(String colorKey, float alpha) { color = Color.argb((int) (Color.alpha(color) / 2 * colorAlpha), Color.red(color), Color.green(color), Color.blue(color)); float centerX = (1.0f - w) / 2; placeholderGradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{0x00000000, 0x00000000, color, 0x00000000, 0x00000000}, new float[]{0.0f, centerX - w / 2.0f, centerX, centerX + w / 2.0f, 1.0f}, Shader.TileMode.REPEAT); - backgroundGradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{color, color}, null, Shader.TileMode.REPEAT); + if (Build.VERSION.SDK_INT >= 28) { + backgroundGradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{color, color}, null, Shader.TileMode.REPEAT); + } else { + if (backgroundBitmap == null) { + backgroundBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + backgroundCanvas = new Canvas(backgroundBitmap); + } + backgroundCanvas.drawColor(color); + backgroundGradient = new BitmapShader(backgroundBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); + } placeholderMatrix = new Matrix(); placeholderGradient.setLocalMatrix(placeholderMatrix); for (Paint paint : paints.values()) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java index 3d93c14e0e7..4ea482992fc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPBaseService.java @@ -135,6 +135,7 @@ public abstract class VoIPBaseService extends Service implements SensorEventList protected int currentState = 0; protected Notification ongoingCallNotification; protected NativeInstance tgVoip; + protected boolean wasConnected; protected TLRPC.Chat chat; @@ -161,7 +162,7 @@ public abstract class VoIPBaseService extends Service implements SensorEventList protected int spConnectingId; protected int spPlayID; protected boolean needPlayEndSound; - protected boolean haveAudioFocus; + protected boolean hasAudioFocus; protected boolean micMute; protected boolean unmutedByHold; protected BluetoothAdapter btAdapter; @@ -819,7 +820,7 @@ public void onDestroy() { am.abandonAudioFocus(this); } am.unregisterMediaButtonEventReceiver(new ComponentName(this, VoIPMediaButtonReceiver.class)); - if (haveAudioFocus) { + if (hasAudioFocus) { am.abandonAudioFocus(this); } Utilities.globalQueue.postRunnable(() -> soundPool.release()); @@ -1111,9 +1112,9 @@ public boolean isBluetoothHeadsetConnected() { public void onAudioFocusChange(int focusChange) { if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { - haveAudioFocus = true; + hasAudioFocus = true; } else { - haveAudioFocus = false; + hasAudioFocus = false; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java index fc7d74c18bd..f8a5f0397cd 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/voip/VoIPService.java @@ -1341,6 +1341,7 @@ private void createGroupInstance() { tgVoip.stopGroup(); } cancelGroupCheckShortPoll(); + wasConnected = false; tgVoip = NativeInstance.makeGroup(this::startGroupCall, (uids, levels, voice) -> { if (sharedInstance == null || groupCall == null) { return; @@ -1377,10 +1378,12 @@ private void createGroupInstance() { if (state == 0) { startGroupCheckShortpoll(); if (playedConnectedSound && spPlayID == 0) { - if (spPlayID != 0) { - soundPool.stop(spPlayID); - } - spPlayID = soundPool.play(spVoiceChatConnecting, 1.0f, 1.0f, 0, -1, 1); + Utilities.globalQueue.postRunnable(() -> { + if (spPlayID != 0) { + soundPool.stop(spPlayID); + } + spPlayID = soundPool.play(spVoiceChatConnecting, 1.0f, 1.0f, 0, -1, 1); + }); } } else { cancelGroupCheckShortPoll(); @@ -1399,6 +1402,12 @@ private void createGroupInstance() { Utilities.globalQueue.postRunnable(() -> soundPool.play(spVoiceChatStartId, 1.0f, 1.0f, 0, 0, 1)); playedConnectedSound = true; } + if (!wasConnected) { + if (!micMute) { + tgVoip.setMuteMicrophone(false); + } + wasConnected = true; + } } }); dispatchStateChanged(STATE_WAIT_INIT); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java index 27769ed1e1e..fcd32b718df 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -51,6 +51,7 @@ import android.widget.TextView; import androidx.core.graphics.ColorUtils; +import androidx.core.view.ViewCompat; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ImageLocation; @@ -811,6 +812,14 @@ public boolean onPreDraw() { checkClearButton(); } + public static boolean checkRtl (String string) { + if (TextUtils.isEmpty(string)) { + return false; + } + char c = string.charAt(0); + return c >= 0x590 && c <= 0x6ff; + } + public void setClearsTextOnSearchCollapse(boolean value) { clearsTextOnSearchCollapse = value; @@ -948,7 +957,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ignoreRequestLayout = true; measureChildWithMargins(searchFilterLayout, widthMeasureSpec, width, heightMeasureSpec, 0); int filterWidth = searchFilterLayout.getVisibility() == View.VISIBLE ? searchFilterLayout.getMeasuredWidth() : 0; - measureChildWithMargins(searchField, MeasureSpec.makeMeasureSpec(minWidth - AndroidUtilities.dp(6), MeasureSpec.UNSPECIFIED), width + filterWidth, heightMeasureSpec, 0); + measureChildWithMargins(searchField, MeasureSpec.makeMeasureSpec(minWidth - AndroidUtilities.dp(12), MeasureSpec.UNSPECIFIED), width + filterWidth, heightMeasureSpec, 0); ignoreRequestLayout = false; setMeasuredDimension(Math.max(filterWidth + searchField.getMeasuredWidth(), minWidth), MeasureSpec.getSize(heightMeasureSpec)); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java index d11e1e79ee7..3bff5aee511 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java @@ -29,7 +29,6 @@ public class AdjustPanLayoutHelper { private final View parent; private View resizableViewToSet; - private ViewGroup decorView; private ViewGroup contentView; private View resizableView; private boolean animationInProgress; @@ -119,7 +118,7 @@ private void animateHeight(int previousHeight, int contentHeight, boolean isKeyb } animator.addUpdateListener(animation -> { float v = (float) animation.getAnimatedValue(); - float y = from * v + to * (1f - v); + float y = (int) (from * v + to * (1f - v)); parent.setTranslationY(y); onPanTranslationUpdate(-y, v, isKeyboardVisible); }); @@ -186,7 +185,7 @@ public void onAttach() { Context context = parent.getContext(); Activity activity = getActivity(context); if (activity != null) { - decorView = (android.view.ViewGroup) activity.getWindow().getDecorView(); + ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); contentView = decorView.findViewById(Window.ID_ANDROID_CONTENT); } resizableView = findResizableView(parent); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index 8b9c0ea7fcf..60255e006f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -289,7 +289,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg TextSelectionHelper.ArticleTextSelectionHelper textSelectionHelper; TextSelectionHelper.ArticleTextSelectionHelper textSelectionHelperBottomSheet; - int allowAnimationIndex = -1; + private int allowAnimationIndex = -1; private final String BOTTOM_SHEET_VIEW_TAG = "bottomSheet"; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index 9f5f4725f1d..6bd6fbbb7a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -624,7 +624,7 @@ private void clearDatabase() { databaseSize = MessagesStorage.getInstance(currentAccount).getDatabaseSize(); listAdapter.notifyDataSetChanged(); } - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didDatabaseCleared); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.didClearDatabase); }); } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java index d97b31ad9d4..22eed70baf3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CancelAccountDeletionActivity.java @@ -155,7 +155,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); doneButton.setVisibility(View.GONE); ScrollView scrollView = new ScrollView(context) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java index 3c0fdb171cd..acaa813a007 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java @@ -84,7 +84,7 @@ public SharingLiveLocationCell(Context context, boolean distance, int padding) { distanceTextView = new SimpleTextView(context); distanceTextView.setTextSize(14); - distanceTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); + distanceTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); distanceTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); addView(distanceTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? padding : 73, 37, LocaleController.isRTL ? 73 : padding, 0)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangeNameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangeNameActivity.java index 8688e91b8b3..67e8ecacb0f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChangeNameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangeNameActivity.java @@ -65,7 +65,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); if (user == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java index 00fab87b1eb..94eef49e2d7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java @@ -157,7 +157,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); ScrollView scrollView = new ScrollView(context) { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangeUsernameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangeUsernameActivity.java index 855fffc1baa..4858c92114d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChangeUsernameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangeUsernameActivity.java @@ -131,7 +131,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); if (user == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java index d0d43f4ca53..bc5604c6715 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java @@ -267,6 +267,7 @@ public void onFragmentDestroy() { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.messagePlayingDidReset); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.messagePlayingProgressDidChanged); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewWallpapper); + getNotificationCenter().onAnimationFinish(allowAnimationIndex); } private void updateEmptyPlaceholder() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java index c4d32f869a4..eb9c1b0dfdf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java @@ -310,7 +310,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); if (currentStep == 0) { actionBar.setTitle(LocaleController.getString("NewChannel", R.string.NewChannel)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 1c1b0df4ce5..792d6b0eb8d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -404,6 +404,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private int threadMaxOutboxReadId; private int replyMaxReadId = 0; private Runnable delayedReadRunnable; + private SparseArray pendingSendMessagesDict = new SparseArray<>(); + private ArrayList pendingSendMessages = new ArrayList<>(); private ArrayList animatingMessageObjects = new ArrayList<>(); private HashMap animatingDocuments = new HashMap<>(); @@ -527,6 +529,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean hasAllMentionsLocal; private SparseArray[] messagesDict = new SparseArray[]{new SparseArray<>(), new SparseArray<>()}; + private SparseArray repliesMessagesDict = new SparseArray<>(); private HashMap> messagesByDays = new HashMap<>(); protected ArrayList messages = new ArrayList<>(); private SparseArray waitingForReplies = new SparseArray<>(); @@ -633,7 +636,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private int distanceToPeer; - private int chatListViewPaddingTop; + private float chatListViewPaddingTop; private int chatListViewPaddingVisibleOffset; private int contentPaddingTop; @@ -649,6 +652,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private int transitionAnimationIndex; private int scrollAnimationIndex; + private int scrollCallbackAnimationIndex; + private final static int[] allowedNotificationsDuringChatListAnimations = new int[]{ NotificationCenter.messagesRead, NotificationCenter.threadMessagesRead, @@ -697,7 +702,7 @@ public boolean needPostpone(int id, int currentAccount, Object[] args) { private boolean scrollByTouch; private ChatActionCell infoTopView1; - public int getChatListViewPadding() { + public float getChatListViewPadding() { return chatListViewPaddingTop; } @@ -1114,7 +1119,6 @@ public boolean onFragmentCreate() { int migrated_to = arguments.getInt("migrated_to", 0); scrollToTopOnResume = arguments.getBoolean("scrollToTopOnResume", false); needRemovePreviousSameChatActivity = arguments.getBoolean("need_remove_previous_same_chat_activity", true); - if (chatId != 0) { currentChat = getMessagesController().getChat(chatId); if (currentChat == null) { @@ -1496,6 +1500,7 @@ public void onFragmentDestroy() { } getNotificationCenter().onAnimationFinish(transitionAnimationIndex); getNotificationCenter().onAnimationFinish(scrollAnimationIndex); + getNotificationCenter().onAnimationFinish(scrollCallbackAnimationIndex); hideUndoViews(); if (chatInviteRunnable != null) { AndroidUtilities.cancelRunOnUIThread(chatInviteRunnable); @@ -3359,7 +3364,7 @@ protected void dispatchDraw(Canvas canvas) { View child = getChildAt(a); if (chatAdapter.isBot && child instanceof BotHelpCell) { BotHelpCell botCell = (BotHelpCell) child; - int top = getMeasuredHeight() / 2 - child.getMeasuredHeight() / 2 + chatListViewPaddingTop; + float top = getMeasuredHeight() / 2 - child.getMeasuredHeight() / 2 + chatListViewPaddingTop; if (!botCell.animating() && !chatListView.fastScrollAnimationRunning) { if (child.getTop() > top) { child.setTranslationY(top - child.getTop()); @@ -4106,7 +4111,7 @@ public void endAnimations() { @Override public int getStarForFixGap() { - int padding = chatListViewPaddingTop; + int padding = (int) chatListViewPaddingTop; if (isThreadChat() && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { padding -= Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); } @@ -4116,7 +4121,7 @@ public int getStarForFixGap() { @Override protected int getParentStart() { if (computingScroll) { - return chatListViewPaddingTop; + return (int) chatListViewPaddingTop; } return 0; } @@ -4124,7 +4129,7 @@ protected int getParentStart() { @Override public int getStartAfterPadding() { if (computingScroll) { - return chatListViewPaddingTop; + return (int) chatListViewPaddingTop; } return super.getStartAfterPadding(); } @@ -4132,7 +4137,7 @@ public int getStartAfterPadding() { @Override public int getTotalSpace() { if (computingScroll) { - return getHeight() - chatListViewPaddingTop - getPaddingBottom(); + return (int) (getHeight() - chatListViewPaddingTop - getPaddingBottom()); } return super.getTotalSpace(); } @@ -4164,7 +4169,7 @@ public int computeVerticalScrollRange(RecyclerView.State state) { @Override public void scrollToPositionWithOffset(int position, int offset, boolean bottom) { if (!bottom) { - offset = offset - getPaddingTop() + chatListViewPaddingTop; + offset = (int) (offset - getPaddingTop() + chatListViewPaddingTop); } super.scrollToPositionWithOffset(position, offset, bottom); } @@ -4238,13 +4243,13 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi int n = chatListView.getChildCount(); for (int i = 0; i < n; i++) { View child = chatListView.getChildAt(i); - int padding = chatListViewPaddingTop; + float padding = chatListViewPaddingTop; if (isThreadChat() && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { padding -= Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); } if (chatListView.getChildAdapterPosition(child) == chatAdapter.getItemCount() - 1) { if (child.getTop() - dy > padding) { - dy = child.getTop() - padding; + dy = (int) (child.getTop() - padding); } return super.scrollVerticallyBy(dy, recycler, state); } @@ -4848,6 +4853,7 @@ public void requestLayout() { closeReportSpam = new ImageView(context); closeReportSpam.setImageResource(R.drawable.miniplayer_close); + closeReportSpam.setContentDescription(LocaleController.getString("Close", R.string.Close)); if (Build.VERSION.SDK_INT >= 21) { closeReportSpam.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_chat_topPanelClose) & 0x19ffffff)); } @@ -6838,6 +6844,9 @@ private void searchUserMessages(TLRPC.User user, TLRPC.Chat chat) { private Animator infoTopViewAnimator; private void updateInfoTopView(boolean animated) { + if (contentView == null) { + return; + } SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); distanceToPeer = preferences.getInt("dialog_bar_distance" + dialog_id, -1); @@ -7118,8 +7127,8 @@ private void updateChatListViewTopPadding() { if (pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { pinnedViewH = Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); } - int oldPadding = chatListViewPaddingTop; - chatListViewPaddingTop = (int) (AndroidUtilities.dp(4) + contentPaddingTop + topPanelViewH + pinnedViewH); + float oldPadding = chatListViewPaddingTop; + chatListViewPaddingTop = AndroidUtilities.dp(4) + contentPaddingTop + topPanelViewH + pinnedViewH; chatListViewPaddingVisibleOffset = 0; chatListViewPaddingTop += contentPanTranslation + bottomPanelTranslationY; if (bottomPanelTranslationY == 0 && !chatActivityEnterView.pannelAniamationInProgress() && contentView.getLayoutParams().height < 0) { @@ -7182,7 +7191,7 @@ private void updateChatListViewTopPadding() { invalidateMessagesVisiblePart(); } - chatListView.setTopGlowOffset(chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4)); + chatListView.setTopGlowOffset((int) (chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4))); if (oldPadding != chatListViewPaddingTop) { int n = chatListView.getChildCount(); @@ -7190,12 +7199,12 @@ private void updateChatListViewTopPadding() { View child = chatListView.getChildAt(i); int adapterPosition = chatListView.getChildAdapterPosition(child); if (adapterPosition == chatAdapter.getItemCount() - 1) { - int padding = chatListViewPaddingTop; + float padding = chatListViewPaddingTop; if (isThreadChat() && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { padding -= Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); } if (child.getTop() > padding) { - chatListView.scrollBy(0, child.getTop() - padding); + chatListView.scrollBy(0, (int) (child.getTop() - padding)); } break; } @@ -7203,7 +7212,7 @@ private void updateChatListViewTopPadding() { } if (!isThreadChat() && !wasManualScroll && unreadMessageObject != null && chatListView != null) { - chatListView.scrollBy(0, oldPadding - chatListViewPaddingTop); + chatListView.scrollBy(0, (int) (oldPadding - chatListViewPaddingTop)); } } @@ -9798,6 +9807,7 @@ public void updateMessagesVisiblePart(boolean inLayout) { boolean previousThreadMessageVisible = threadMessageVisible; int previousPinnedMessageId = currentPinnedMessageId; int maxVisibleId = Integer.MIN_VALUE; + MessageObject maxVisibleMessageObject = null; threadMessageVisible = firstLoading; Integer currentReadMaxId; @@ -9832,14 +9842,17 @@ public void updateMessagesVisiblePart(boolean inLayout) { if (view instanceof ChatMessageCell) { ChatMessageCell messageCell = (ChatMessageCell) view; messageObject = messageCell.getMessageObject(); - maxVisibleId = Math.max(maxVisibleId, messageObject.getId()); + if (messageObject.getId() > maxVisibleId) { + maxVisibleId = messageObject.getId(); + maxVisibleMessageObject = messageObject; + } int viewTop = top >= 0 ? 0 : -top; int viewBottom = messageCell.getMeasuredHeight(); if (viewBottom > height) { viewBottom = viewTop + height; } - messageCell.setVisiblePart(viewTop, viewBottom - viewTop, recyclerChatViewHeight, contentView.getKeyboardHeight()); + messageCell.setVisiblePart(viewTop, viewBottom - viewTop, recyclerChatViewHeight, contentView.getKeyboardHeight()); if (!threadMessageVisible && threadMessageObject != null && messageObject == threadMessageObject && messageCell.getBottom() > chatListViewPaddingTop) { threadMessageVisible = true; @@ -9908,14 +9921,34 @@ public void updateMessagesVisiblePart(boolean inLayout) { } } currentPinnedMessageId = 0; - if (maxVisibleId == Integer.MIN_VALUE) { - if (startLoadFromMessageId != 0) { - maxVisibleId = startLoadFromMessageId; - } else if (!pinnedMessageIds.isEmpty()) { - maxVisibleId = pinnedMessageIds.get(0) + 1; - } - } if (!pinnedMessageIds.isEmpty()) { + if (maxVisibleId == Integer.MIN_VALUE) { + if (startLoadFromMessageId != 0) { + maxVisibleId = startLoadFromMessageId; + } else if (!pinnedMessageIds.isEmpty()) { + maxVisibleId = pinnedMessageIds.get(0) + 1; + } + } else if (maxVisibleId < 0) { + int idx = messages.indexOf(maxVisibleMessageObject); + if (idx >= 0) { + for (int a = idx - 1; a >= 0; a--) { + MessageObject object = messages.get(a); + if (object.getId() > 0) { + maxVisibleId = object.getId(); + break; + } + } + if (maxVisibleId < 0) { + for (int a = idx + 1, N = messages.size(); a < N; a++) { + MessageObject object = messages.get(a); + if (object.getId() > 0) { + maxVisibleId = object.getId(); + break; + } + } + } + } + } currentPinnedMessageId = findClosest(pinnedMessageIds, forceNextPinnedMessageId != 0 ? forceNextPinnedMessageId : maxVisibleId, currentPinnedMessageIndex); if (!loadingPinnedMessagesList && !pinnedEndReached && !pinnedMessageIds.isEmpty() && currentPinnedMessageIndex[0] > pinnedMessageIds.size() - 2) { getMediaDataController().loadPinnedMessages(dialog_id, pinnedMessageIds.get(pinnedMessageIds.size() - 1), 0); @@ -10055,7 +10088,7 @@ public void updateMessagesVisiblePart(boolean inLayout) { floatingDateView.setTranslationY(chatListView.getTranslationY() + chatListViewPaddingTop + floatingDateViewOffset - AndroidUtilities.dp(4)); } invalidateChatListViewTopPadding(); - if (!firstLoading && !paused && !inPreviewMode && fragmentOpened && chatMode == 0 && !getMessagesController().ignoreSetOnline) { + if (!firstLoading && !paused && !inPreviewMode && (fragmentOpened || inBubbleMode) && chatMode == 0 && !getMessagesController().ignoreSetOnline) { int scheduledRead = 0; if ((maxPositiveUnreadId != Integer.MIN_VALUE || maxNegativeUnreadId != Integer.MAX_VALUE)) { int counterDecrement = 0; @@ -10184,7 +10217,7 @@ private void toggleMute(boolean instant) { private int getScrollOffsetForMessage(MessageObject object) { int exactlyHeight = getHeightForMessage(object); - return Math.max(-AndroidUtilities.dp(2), (chatListView.getMeasuredHeight() - chatListViewPaddingTop - exactlyHeight) / 2); + return (int) Math.max(-AndroidUtilities.dp(2), (chatListView.getMeasuredHeight() - chatListViewPaddingTop - exactlyHeight) / 2); } private int getHeightForMessage(MessageObject object) { @@ -10330,7 +10363,7 @@ public void scrollToMessageId(int id, int fromMessageId, boolean select, int loa if (found) { int yOffset = getScrollOffsetForMessage(object); - int scrollY = view.getTop() - chatListViewPaddingTop - yOffset; + int scrollY = (int) (view.getTop() - chatListViewPaddingTop - yOffset); int maxScrollOffset = chatListView.computeVerticalScrollRange() - chatListView.computeVerticalScrollOffset() - chatListView.computeVerticalScrollExtent(); if (maxScrollOffset < 0) maxScrollOffset = 0; if (scrollY > maxScrollOffset) { @@ -10349,7 +10382,7 @@ public void scrollToMessageId(int id, int fromMessageId, boolean select, int loa chatScrollHelperCallback.scrollTo = object; chatScrollHelperCallback.lastBottom = false; chatScrollHelperCallback.lastItemOffset = yOffset; - chatScrollHelperCallback.lastPadding = chatListViewPaddingTop; + chatScrollHelperCallback.lastPadding = (int) chatListViewPaddingTop; chatScrollHelper.setScrollDirection(scrollDirection); chatScrollHelper.scrollToPosition(position, yOffset, false, true); canShowPagedownButton = true; @@ -11453,7 +11486,7 @@ private PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageOb if (view instanceof ChatActionCell && currentChat != null) { object.dialogId = -currentChat.id; } - object.clipTopAddition = chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4); + object.clipTopAddition = (int) (chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4)); return object; } } @@ -11877,6 +11910,28 @@ public void didReceivedNotification(int id, int account, final Object... args) { endReached[loadIndex] = true; } + if (isThreadChat() && load_type == 0 && forwardEndReached[0] && !pendingSendMessages.isEmpty()) { + int pasteIndex = 0; + int date = pendingSendMessages.get(0).messageOwner.date; + if (!messArr.isEmpty()) { + if (date >= messArr.get(0).messageOwner.date) { + pasteIndex = 0; + } else if (date <= messArr.get(messArr.size() - 1).messageOwner.date) { + pasteIndex = messArr.size(); + } else { + for (int a = 0, N = messArr.size(); a < N - 1; a++) { + if (messArr.get(a).messageOwner.date >= date && messArr.get(a + 1).messageOwner.date <= date) { + pasteIndex = a + 1; + } + } + } + } + messArr = new ArrayList<>(messArr); + messArr.addAll(pasteIndex, pendingSendMessages); + pendingSendMessages.clear(); + pendingSendMessagesDict.clear(); + } + if (!threadMessageAdded && isThreadChat() && (load_type == 0 && messArr.size() < count || (load_type == 2 || load_type == 3) && endReached[0])) { TLRPC.Message msg = new TLRPC.TL_message(); if (threadMessageObject.getRepliesCount() == 0) { @@ -11933,6 +11988,9 @@ public void didReceivedNotification(int id, int account, final Object... args) { } for (int a = 0; a < messArr.size(); a++) { MessageObject obj = messArr.get(a); + if (obj.replyMessageObject != null) { + repliesMessagesDict.put(obj.replyMessageObject.getId(), obj.replyMessageObject); + } int messageId = obj.getId(); if (threadMessageId != 0) { if (messageId <= (obj.isOut() ? threadMaxOutboxReadId : threadMaxInboxReadId)) { @@ -12437,7 +12495,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { chatScrollHelperCallback.scrollTo = null; chatScrollHelperCallback.lastBottom = true; chatScrollHelperCallback.lastItemOffset = 0; - chatScrollHelperCallback.lastPadding = chatListViewPaddingTop; + chatScrollHelperCallback.lastPadding = (int) chatListViewPaddingTop; chatScrollHelper.scrollToPosition(0, 0, true, true); } else { MessageObject object = messagesDict[loadIndex].get(postponedScrollMessageId); @@ -12476,7 +12534,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { chatScrollHelperCallback.scrollTo = object; chatScrollHelperCallback.lastBottom = false; chatScrollHelperCallback.lastItemOffset = yOffset; - chatScrollHelperCallback.lastPadding = chatListViewPaddingTop; + chatScrollHelperCallback.lastPadding = (int) chatListViewPaddingTop; chatScrollHelper.scrollToPosition(chatAdapter.messagesStartRow + k, yOffset, false, true); } } @@ -12872,6 +12930,13 @@ public void didReceivedNotification(int id, int account, final Object... args) { } Integer msgId = (Integer) args[0]; MessageObject obj = messagesDict[0].get(msgId); + if (isThreadChat() && pendingSendMessagesDict.size() > 0) { + MessageObject object = pendingSendMessagesDict.get(msgId); + if (object != null) { + Integer newMsgId = (Integer) args[1]; + pendingSendMessagesDict.put(newMsgId, object); + } + } if (obj != null) { if (obj.shouldRemoveVideoEditedInfo) { obj.videoEditedInfo = null; @@ -13540,6 +13605,11 @@ public void didReceivedNotification(int id, int account, final Object... args) { } else if (id == NotificationCenter.replyMessagesDidLoad) { long did = (Long) args[0]; if (did == dialog_id) { + ArrayList loadedMessages = (ArrayList) args[1]; + for (int a = 0, N = loadedMessages.size(); a < N; a++) { + MessageObject obj = loadedMessages.get(a); + repliesMessagesDict.put(obj.getId(), obj); + } updateVisibleRows(); } else if (waitingForReplies.size() != 0 && ChatObject.isChannel(currentChat) && !currentChat.megagroup && chatInfo != null && did == -chatInfo.linked_chat_id) { checkWaitingForReplies(); @@ -14349,13 +14419,17 @@ private void processNewMessages(ArrayList arr) { boolean notifiedSearch = false; LongSparseArray scheduledGroupReplacement = null; - for (int a = 0; a < arr.size(); a++) { + for (int a = 0, N = arr.size(); a < N; a++) { MessageObject messageObject = arr.get(a); int messageId = messageObject.getId(); if (threadMessageId != 0) { if (messageId > 0 && messageId <= (messageObject.isOut() ? threadMaxOutboxReadId : threadMaxInboxReadId)) { messageObject.setIsRead(); } + if (!forwardEndReached[0] && messageId < 0) { + pendingSendMessagesDict.put(messageId, messageObject); + pendingSendMessages.add(messageObject); + } } if (messageObject.isDice() && !messageObject.isForwarded()) { messageObject.wasUnread = true; @@ -14420,6 +14494,9 @@ private void processNewMessages(ArrayList arr) { } if (messageObject.getReplyMsgId() != 0 && messageObject.replyMessageObject == null) { messageObject.replyMessageObject = messagesDict[0].get(messageObject.getReplyMsgId()); + if (messageObject.replyMessageObject == null && messageObject.getDialogId() != mergeDialogId) { + messageObject.replyMessageObject = repliesMessagesDict.get(messageObject.getReplyMsgId()); + } if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { messageObject.generatePinMessageText(null, null); } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGameScore) { @@ -14942,17 +15019,20 @@ private void processDeletedMessages(ArrayList markAsDeletedMessages, in for (int a = 0; a < size; a++) { Integer mid = markAsDeletedMessages.get(a); MessageObject obj = messagesDict[loadIndex].get(mid); - if (loadIndex == 0 && pinnedMessageObjects.containsKey(mid)) { - pinnedMessageObjects.remove(mid); - pinnedMessageIds.remove(mid); - loadedPinnedMessagesCount = pinnedMessageIds.size(); - totalPinnedMessagesCount--; - if (totalPinnedMessagesCount < 0) { - totalPinnedMessagesCount = 0; - } - if (currentPinnedMessageId == mid) { - currentPinnedMessageId = 0; + if (loadIndex == 0) { + if (pinnedMessageObjects.containsKey(mid)) { + pinnedMessageObjects.remove(mid); + pinnedMessageIds.remove(mid); + loadedPinnedMessagesCount = pinnedMessageIds.size(); + totalPinnedMessagesCount--; + if (totalPinnedMessagesCount < 0) { + totalPinnedMessagesCount = 0; + } + if (currentPinnedMessageId == mid) { + currentPinnedMessageId = 0; + } } + repliesMessagesDict.remove(mid); } if (obj != null) { if (obj.messageOwner.reply_to != null && !(obj.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage)) { @@ -15152,6 +15232,9 @@ private void replaceMessageObjects(ArrayList messageObjects, int updatePinnedMessageView(true); } } + if (loadIndex == 0 && repliesMessagesDict.indexOfKey(messageObject.getId()) >= 0) { + repliesMessagesDict.put(messageObject.getId(), messageObject); + } if (old == null || remove && old.messageOwner.date != messageObject.messageOwner.date) { continue; } @@ -21627,12 +21710,10 @@ public class ChatScrollCallback extends RecyclerAnimationScrollHelper.AnimationC private boolean lastBottom; private int lastPadding; - int animationIndex; - @Override public void onStartAnimation() { super.onStartAnimation(); - animationIndex = getNotificationCenter().setAnimationInProgress(animationIndex, allowedNotificationsDuringChatListAnimations); + scrollCallbackAnimationIndex = getNotificationCenter().setAnimationInProgress(scrollCallbackAnimationIndex, allowedNotificationsDuringChatListAnimations); } @Override @@ -21641,7 +21722,7 @@ public void onEndAnimation() { chatAdapter.updateRowsSafe(); int lastItemPosition = chatAdapter.messagesStartRow + messages.indexOf(scrollTo); if (lastItemPosition >= 0) { - chatLayoutManager.scrollToPositionWithOffset(lastItemPosition, lastItemOffset + lastPadding - chatListViewPaddingTop, lastBottom); + chatLayoutManager.scrollToPositionWithOffset(lastItemPosition, (int) (lastItemOffset + lastPadding - chatListViewPaddingTop), lastBottom); } } else { chatAdapter.updateRowsSafe(); @@ -21653,7 +21734,7 @@ public void onEndAnimation() { updateVisibleRows(); - AndroidUtilities.runOnUIThread(() -> getNotificationCenter().onAnimationFinish(animationIndex)); + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().onAnimationFinish(scrollCallbackAnimationIndex)); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java index d17584b196f..80330fbeba7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java @@ -192,7 +192,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); fragmentView = new ScrollView(context) { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java index 2a0f4a994ef..d2daab56de1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java @@ -545,7 +545,7 @@ private void linkChat(TLRPC.Chat chat, BaseFragment createFragment) { } else { finishFragment(); } - })); + }), ConnectionsManager.RequestFlagInvokeAfter); AndroidUtilities.runOnUIThread(() -> { if (progressDialog[0] == null) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index 30b999ddd50..f15777b3d06 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -777,6 +777,18 @@ public void didAddParticipantToList(int uid, TLObject participant) { public void didChangeOwner(TLRPC.User user) { onOwnerChaged(user); } + + @Override + public void didSelectUser(int uid) { + final TLRPC.User user = getMessagesController().getUser(uid); + if (user != null) { + AndroidUtilities.runOnUIThread(() -> { + if (BulletinFactory.canShowBulletin(ChatUsersActivity.this)) { + BulletinFactory.createPromoteToAdminBulletin(ChatUsersActivity.this, user.first_name).show(); + } + }, 200); + } + } }); fragment.setInfo(info); presentFragment(fragment); @@ -1292,6 +1304,9 @@ public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC channelParticipant.banned_rights = rightsBanned; channelParticipant.rank = rank; } + if (delegate != null && rights == 1) { + delegate.didSelectUser(user_id); + } if (removeFragment) { removeSelfFromStack(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java index f24d56f8e26..5ab56a1048e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java @@ -1687,7 +1687,7 @@ public ArrayList getThemeDescriptions() { themeDescriptions.add(new ThemeDescription(searchListView, 0, new Class[]{LocationCell.class}, new String[]{"addressTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{SharingLiveLocationCell.class}, new String[]{"nameTextView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{SharingLiveLocationCell.class}, new String[]{"distanceTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText2)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{SharingLiveLocationCell.class}, new String[]{"distanceTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{LocationLoadingCell.class}, new String[]{"progressBar"}, null, null, null, Theme.key_progressCircle)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{LocationLoadingCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java index ef019acc481..4b140cbee09 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -20,6 +20,7 @@ import android.text.TextUtils; import android.view.Gravity; import android.view.View; +import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.ImageView; @@ -74,16 +75,31 @@ public ChatAvatarContainer(Context context, ChatActivity chatActivity, boolean n super(context); parentFragment = chatActivity; - avatarImageView = new BackupImageView(context); + final boolean avatarClickable = parentFragment != null && parentFragment.getChatMode() == 0 && !UserObject.isReplyUser(parentFragment.getCurrentUser()); + avatarImageView = new BackupImageView(context) { + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + if (avatarClickable && getImageReceiver().hasNotThumb()) { + info.setText(LocaleController.getString("AccDescrProfilePicture", R.string.AccDescrProfilePicture)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + info.addAction(new AccessibilityNodeInfo.AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, LocaleController.getString("Open", R.string.Open))); + } + } else { + info.setVisibleToUser(false); + } + } + }; if (parentFragment != null) { sharedMediaPreloader = new SharedMediaLayout.SharedMediaPreloader(chatActivity); if (parentFragment.isThreadChat() || parentFragment.getChatMode() == 2) { avatarImageView.setVisibility(GONE); } } + avatarImageView.setContentDescription(LocaleController.getString("AccDescrProfilePicture", R.string.AccDescrProfilePicture)); avatarImageView.setRoundRadius(AndroidUtilities.dp(21)); addView(avatarImageView); - if (parentFragment != null && parentFragment.getChatMode() == 0 && !UserObject.isReplyUser(parentFragment.getCurrentUser())) { + if (avatarClickable) { avatarImageView.setOnClickListener(v -> openProfile(true)); } @@ -647,4 +663,12 @@ private void updateCurrentConnectionState() { subtitleTextView.setTag(Theme.key_actionBarDefaultSubtitle); } } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + if (info.isClickable() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + info.addAction(new AccessibilityNodeInfo.AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, LocaleController.getString("OpenProfile", R.string.OpenProfile))); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java index ae9b9dd0f62..67be47743a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java @@ -1316,10 +1316,6 @@ public void onAnimationEnd(Animator animation) { animatorSet = null; } final int currentAccount = account; - if (animatorSet != null) { - animatorSet.cancel(); - animatorSet = null; - } animationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(animationIndex, null); animatorSet = new AnimatorSet(); animatorSet.playTogether(ObjectAnimator.ofFloat(this, "topPadding", 0)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPip.java index 6740759f0d5..698f63bf82d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPip.java @@ -239,6 +239,11 @@ public boolean onTouchEvent(MotionEvent event) { AndroidUtilities.cancelRunOnUIThread(micRunnable); AndroidUtilities.cancelRunOnUIThread(pressedRunnable); if (animateToPrepareRemove) { + if (pressed) { + if (VoIPService.getSharedInstance() != null) { + VoIPService.getSharedInstance().setMicMute(true, false, false); + } + } pressed = false; remove(); return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java index 836a1795f3e..21b99885045 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java @@ -1044,6 +1044,10 @@ protected void onOpenCloseStickersAlert(boolean open) { } + protected void onTextAdd() { + + } + private Size baseStickerSize() { float side = (float) Math.floor(getPaintingSize().width * 0.5); return new Size(side, side); @@ -1081,6 +1085,7 @@ private void mirrorSticker() { } private TextPaintView createText(boolean select) { + onTextAdd(); Swatch currentSwatch = colorPicker.getSwatch(); Swatch swatch; if (selectedTextType == 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java index 4ef64bac65c..652fb0f1c8b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -340,8 +340,8 @@ private void showActionMode(boolean show) { actionMode.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 72, 0, 0, 0)); selectedMessagesCountTextView.setOnTouchListener((v, event) -> true); - gotoItem = actionMode.addItemWithWidth(gotoItemId, R.drawable.msg_message, AndroidUtilities.dp(54)); - forwardItem = actionMode.addItemWithWidth(forwardItemId, R.drawable.msg_forward, AndroidUtilities.dp(54)); + gotoItem = actionMode.addItemWithWidth(gotoItemId, R.drawable.msg_message, AndroidUtilities.dp(54), LocaleController.getString("AccDescrGoToMessage", R.string.AccDescrGoToMessage)); + forwardItem = actionMode.addItemWithWidth(forwardItemId, R.drawable.msg_forward, AndroidUtilities.dp(54), LocaleController.getString("Forward", R.string.Forward)); } if (parent.getActionBar().getBackButton().getDrawable() instanceof MenuDrawable) { parent.getActionBar().setBackButtonDrawable(new BackDrawable(false)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java index ca548ac6473..214f738c234 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java @@ -57,9 +57,6 @@ public class VoIPToggleButton extends FrameLayout { private float crossProgress; private boolean drawCross; - private Bitmap iconBitmap; - private Canvas iconCanvas; - private float crossOffset; Drawable rippleDrawable; @@ -144,14 +141,6 @@ protected void onDraw(Canvas canvas) { } icon[0].setAlpha(255); - if (iconBitmap == null) { - iconBitmap = Bitmap.createBitmap(AndroidUtilities.dp(32), AndroidUtilities.dp(32), Bitmap.Config.ARGB_8888); - iconCanvas = new Canvas(iconBitmap); - } else { - iconBitmap.eraseColor(Color.TRANSPARENT); - } - float x = iconBitmap.getWidth() >> 1; - float y = iconBitmap.getHeight() >> 1; if (replaceProgress != 0 && iconChangeColor) { int color = ColorUtils.blendARGB(replaceColorFrom, currentIconColor, replaceProgress); icon[0].setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); @@ -175,8 +164,8 @@ protected void onDraw(Canvas canvas) { } } if (crossProgress > 0) { - int left = (int) (x - icon[0].getIntrinsicWidth() / 2f); - int top = (int) (x - icon[0].getIntrinsicHeight() / 2); + int left = (int) (cx - icon[0].getIntrinsicWidth() / 2f); + int top = (int) (cy - icon[0].getIntrinsicHeight() / 2); float startX = left + AndroidUtilities.dpf2(8) + crossOffset; float startY = top + AndroidUtilities.dpf2(8); @@ -184,15 +173,16 @@ protected void onDraw(Canvas canvas) { float endX = startX - AndroidUtilities.dp(1) + AndroidUtilities.dp(17) * CubicBezierInterpolator.DEFAULT.getInterpolation(crossProgress); float endY = startY + AndroidUtilities.dp(17) * CubicBezierInterpolator.DEFAULT.getInterpolation(crossProgress); + canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), 255, Canvas.ALL_SAVE_FLAG); icon[0].setBounds( - (int) (x - icon[0].getIntrinsicWidth() / 2f), (int) (y - icon[0].getIntrinsicHeight() / 2), - (int) (x + icon[0].getIntrinsicWidth() / 2), (int) (y + icon[0].getIntrinsicHeight() / 2) + (int) (cx - icon[0].getIntrinsicWidth() / 2f), (int) (cy - icon[0].getIntrinsicHeight() / 2), + (int) (cx + icon[0].getIntrinsicWidth() / 2), (int) (cy + icon[0].getIntrinsicHeight() / 2) ); - icon[0].draw(iconCanvas); + icon[0].draw(canvas); - iconCanvas.drawLine(startX, startY - AndroidUtilities.dp(2f), endX, endY - AndroidUtilities.dp(2f), xRefPaint); - iconCanvas.drawLine(startX, startY, endX, endY, crossPaint); - canvas.drawBitmap(iconBitmap, cx - x, cy - y, bitmapPaint); + canvas.drawLine(startX, startY - AndroidUtilities.dp(2f), endX, endY - AndroidUtilities.dp(2f), xRefPaint); + canvas.drawLine(startX, startY, endX, endY, crossPaint); + canvas.restore(); } else { icon[0].setBounds( (int) (cx - icon[0].getIntrinsicWidth() / 2f), (int) (cy - icon[0].getIntrinsicHeight() / 2), @@ -371,34 +361,37 @@ public void jumpDrawablesToCurrentState() { } } + //animate background if true public void setCheckable(boolean checkable) { this.checkable = checkable; } public void setChecked(boolean checked, boolean animated) { this.checked = checked; - if (animated) { - if (checkAnimator != null) { - checkAnimator.removeAllListeners(); - checkAnimator.cancel(); - } - checkAnimator = ValueAnimator.ofFloat(checkedProgress, checked ? 1f : 0); - checkAnimator.addUpdateListener(valueAnimator -> { - checkedProgress = (float) valueAnimator.getAnimatedValue(); - setBackgroundColor(backgroundCheck1, backgroundCheck2); - }); - checkAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - checkedProgress = checked ? 1f : 0; - setBackgroundColor(backgroundCheck1, backgroundCheck2); + if (checkable) { + if (animated) { + if (checkAnimator != null) { + checkAnimator.removeAllListeners(); + checkAnimator.cancel(); } - }); - checkAnimator.setDuration(150); - checkAnimator.start(); - } else { - checkedProgress = checked ? 1f : 0; - setBackgroundColor(backgroundCheck1, backgroundCheck2); + checkAnimator = ValueAnimator.ofFloat(checkedProgress, checked ? 1f : 0); + checkAnimator.addUpdateListener(valueAnimator -> { + checkedProgress = (float) valueAnimator.getAnimatedValue(); + setBackgroundColor(backgroundCheck1, backgroundCheck2); + }); + checkAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + checkedProgress = checked ? 1f : 0; + setBackgroundColor(backgroundCheck1, backgroundCheck2); + } + }); + checkAnimator.setDuration(150); + checkAnimator.start(); + } else { + checkedProgress = checked ? 1f : 0; + setBackgroundColor(backgroundCheck1, backgroundCheck2); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java index ee4877f39d7..1d3bc859f07 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPWindowView.java @@ -136,11 +136,12 @@ public void finish(long animDuration) { } } else { - animationIndex = NotificationCenter.getInstance(UserConfig.selectedAccount).setAnimationInProgress(animationIndex, null); + int account = UserConfig.selectedAccount; + animationIndex = NotificationCenter.getInstance(account).setAnimationInProgress(animationIndex, null); animate().translationX(getMeasuredWidth()).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - NotificationCenter.getInstance(UserConfig.selectedAccount).onAnimationFinish(animationIndex); + NotificationCenter.getInstance(account).onAnimationFinish(animationIndex); if (getParent() != null) { activity.setRequestedOrientation(orientationBefore); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 8717d8a3fe7..88851c0939f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -147,11 +147,12 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter private boolean checkPermission = true; - private final static int search_button = 0; - private final static int sort_button = 1; private AnimatorSet bounceIconAnimator; private int animationIndex = -1; + private final static int search_button = 0; + private final static int sort_button = 1; + public interface ContactsActivityDelegate { void didSelectContact(TLRPC.User user, String param, ContactsActivity activity); } @@ -207,6 +208,7 @@ public void onFragmentDestroy() { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.closeChats); delegate = null; AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid); + getNotificationCenter().onAnimationFinish(animationIndex); } @Override @@ -1038,7 +1040,7 @@ public void onAnimationEnd(Animator animation) { }); animatorSet.playTogether(valueAnimator); AndroidUtilities.runOnUIThread(() -> { - animationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(animationIndex, null); + animationIndex = getNotificationCenter().setAnimationInProgress(animationIndex, null); animatorSet.start(); if (isOpen) { floatingButton.setAnimation(R.raw.write_contacts_fab_icon, 52, 52); @@ -1178,7 +1180,7 @@ public void onAnimationEnd(Animator animation) { previousFab.setScaleX(1f); previousFab.setScaleY(1f); bounceIconAnimator = null; - NotificationCenter.getInstance(currentAccount).onAnimationFinish(animationIndex); + getNotificationCenter().onAnimationFinish(animationIndex); } }); bounceIconAnimator.start(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index e52e20d0695..7d48c6d88f6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -74,8 +74,6 @@ import androidx.core.graphics.ColorUtils; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; @@ -493,6 +491,9 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == fragmentContextView && fragmentContextView.getCurrentStyle() == 3) { return true; } + if (child == blurredView) { + return true; + } boolean result; if (child == viewPages[0] || (viewPages.length > 1 && child == viewPages[1]) || child == fragmentContextView || child == fragmentLocationContextView) { canvas.save(); @@ -605,6 +606,18 @@ protected void dispatchDraw(Canvas canvas) { fragmentContextView.setDrawOverlay(false); canvas.restore(); } + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + if (blurredView.getAlpha() != 1f) { + if (blurredView.getAlpha() != 0) { + canvas.saveLayerAlpha(blurredView.getLeft(), blurredView.getTop(), blurredView.getRight(), blurredView.getBottom(), (int) (255 * blurredView.getAlpha()), Canvas.ALL_SAVE_FLAG); + canvas.translate(blurredView.getLeft(), blurredView.getTop()); + blurredView.draw(canvas); + canvas.restore(); + } + } else { + blurredView.draw(canvas); + } + } if (scrimView != null) { canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), scrimPaint); canvas.save(); @@ -1622,14 +1635,14 @@ public boolean onFragmentCreate() { getNotificationCenter().addObserver(this, NotificationCenter.messagesDeleted); - getNotificationCenter().addObserver(this, NotificationCenter.didDatabaseCleared); + getNotificationCenter().addObserver(this, NotificationCenter.didClearDatabase); if (!dialogsLoaded[currentAccount]) { MessagesController messagesController = getMessagesController(); messagesController.loadGlobalNotificationsSettings(); messagesController.loadDialogs(folderId, 0, 100, true); messagesController.loadHintDialogs(); - messagesController.loadUserInfo(UserConfig.getInstance(currentAccount).getCurrentUser(), false, classGuid); + messagesController.loadUserInfo(getUserConfig().getCurrentUser(), false, classGuid); getContactsController().checkInviteText(); getMediaDataController().loadRecents(MediaDataController.TYPE_FAVE, false, true, false); getMediaDataController().checkFeaturedStickers(); @@ -1676,13 +1689,14 @@ public void onFragmentDestroy() { NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetPasscode); } - getNotificationCenter().removeObserver(this, NotificationCenter.didDatabaseCleared); + getNotificationCenter().removeObserver(this, NotificationCenter.didClearDatabase); if (commentView != null) { commentView.onDestroy(); } if (undoView[0] != null) { undoView[0].hide(true, 0); } + getNotificationCenter().onAnimationFinish(animationIndex); delegate = null; } @@ -2878,7 +2892,15 @@ public void getOutline(View view, Outline outline) { if (commentView != null) { commentView.onDestroy(); } - commentView = new ChatActivityEnterView(getParentActivity(), contentView, null, false); + commentView = new ChatActivityEnterView(getParentActivity(), contentView, null, false) { + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + } + return super.dispatchTouchEvent(ev); + } + }; commentView.setAllowStickersAndGifs(false, false); commentView.setForceShowSendButton(true, false); commentView.setVisibility(View.GONE); @@ -3054,7 +3076,7 @@ protected boolean canUndo() { actionBarDefaultPaint.setColor(Theme.getColor(folderId == 0 ? Theme.key_actionBarDefault : Theme.key_actionBarDefaultArchived)); if (inPreviewMode) { - final TLRPC.User currentUser = UserConfig.getInstance(currentAccount).getCurrentUser(); + final TLRPC.User currentUser = getUserConfig().getCurrentUser(); avatarContainer = new ChatAvatarContainer(actionBar.getContext(), null, false); avatarContainer.setTitle(UserObject.getUserName(currentUser)); avatarContainer.setSubtitle(LocaleController.formatUserStatus(currentAccount, currentUser)); @@ -3537,7 +3559,7 @@ public void onResume() { } final boolean tosAccepted; if (!afterSignup) { - tosAccepted = UserConfig.getInstance(UserConfig.selectedAccount).unacceptedTermsOfService == null; + tosAccepted = getUserConfig().unacceptedTermsOfService == null; } else { tosAccepted = false; afterSignup = false; @@ -3894,7 +3916,7 @@ public void onAnimationEnd(Animator animation) { searchAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - NotificationCenter.getInstance(currentAccount).onAnimationFinish(animationIndex); + getNotificationCenter().onAnimationFinish(animationIndex); if (searchAnimator != animation) { return; } @@ -3936,7 +3958,7 @@ public void onAnimationEnd(Animator animation) { @Override public void onAnimationCancel(Animator animation) { - NotificationCenter.getInstance(currentAccount).onAnimationFinish(animationIndex); + getNotificationCenter().onAnimationFinish(animationIndex); if (searchAnimator == animation) { if (show) { viewPages[0].listView.hide(); @@ -3947,7 +3969,7 @@ public void onAnimationCancel(Animator animation) { } } }); - animationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(animationIndex, null); + animationIndex = getNotificationCenter().setAnimationInProgress(animationIndex, null); searchAnimator.start(); if (tabsAlphaAnimator != null) { tabsAlphaAnimator.start(); @@ -4014,7 +4036,6 @@ private void updateFilterTabsVisibility(boolean animated) { filterTabsMoveFrom = Math.max(0, AndroidUtilities.dp(44) + actionBar.getTranslationY()); } float animateFromScrollY = actionBar.getTranslationY(); - final int account = currentAccount; filtersTabAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -4026,7 +4047,7 @@ public void onAnimationEnd(Animator animation) { if (fragmentView != null) { fragmentView.requestLayout(); } - NotificationCenter.getInstance(account).onAnimationFinish(animationIndex); + getNotificationCenter().onAnimationFinish(animationIndex); } }); filtersTabAnimator.addUpdateListener(valueAnimator -> { @@ -4040,7 +4061,7 @@ public void onAnimationEnd(Animator animation) { }); filtersTabAnimator.setDuration(220); filtersTabAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); - animationIndex = NotificationCenter.getInstance(account).setAnimationInProgress(animationIndex, null); + animationIndex = getNotificationCenter().setAnimationInProgress(animationIndex, null); filtersTabAnimator.start(); fragmentView.requestLayout(); } else { @@ -4105,7 +4126,7 @@ private void checkListLoad(ViewPage viewPage) { MessagesController.DialogFilter filter = getMessagesController().dialogFilters.get(viewPage.selectedType); if ((filter.flags & MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED) == 0) { if (visibleItemCount > 0 && viewPage.layoutManager.findLastVisibleItemPosition() >= getDialogsArray(currentAccount, viewPage.dialogsType, 1, dialogsListFrozen).size() - 10 || - visibleItemCount == 0 && !MessagesController.getInstance(currentAccount).isDialogsEndReached(1)) { + visibleItemCount == 0 && !getMessagesController().isDialogsEndReached(1)) { loadArchivedFromCache = !getMessagesController().isDialogsEndReached(1); if (loadArchivedFromCache || !getMessagesController().isServerDialogsEndReached(1)) { loadArchived = true; @@ -4115,7 +4136,7 @@ private void checkListLoad(ViewPage viewPage) { } } if (visibleItemCount > 0 && viewPage.layoutManager.findLastVisibleItemPosition() >= getDialogsArray(currentAccount, viewPage.dialogsType, folderId, dialogsListFrozen).size() - 10 || - visibleItemCount == 0 && (viewPage.dialogsType == 7 || viewPage.dialogsType == 8) && !MessagesController.getInstance(currentAccount).isDialogsEndReached(folderId)) { + visibleItemCount == 0 && (viewPage.dialogsType == 7 || viewPage.dialogsType == 8) && !getMessagesController().isDialogsEndReached(folderId)) { loadFromCache = !getMessagesController().isDialogsEndReached(folderId); if (loadFromCache || !getMessagesController().isServerDialogsEndReached(folderId)) { load = true; @@ -4752,7 +4773,7 @@ private void perfromSelectedDialogsAction(int action, boolean alert) { getMessagesController().setDialogsInTransaction(true); perfromSelectedDialogsAction(action, false); getMessagesController().setDialogsInTransaction(false); - MessagesController.getInstance(currentAccount).checkIfFolderEmpty(folderId); + getMessagesController().checkIfFolderEmpty(folderId); if (folderId != 0 && getDialogsArray(currentAccount, viewPages[0].dialogsType, folderId, false).size() == 0) { viewPages[0].listView.setEmptyView(null); viewPages[0].progressView.setVisibility(View.INVISIBLE); @@ -4928,7 +4949,7 @@ private void perfromSelectedDialogsAction(int action, boolean alert) { if (AndroidUtilities.isTablet()) { getNotificationCenter().postNotificationName(NotificationCenter.closeChats, selectedDialog); } - MessagesController.getInstance(currentAccount).checkIfFolderEmpty(folderId); + getMessagesController().checkIfFolderEmpty(folderId); } }); } @@ -5701,7 +5722,7 @@ public void didReceivedNotification(int id, int account, Object... args) { getMessagesController().blockPeer(user.id); } } - MessagesController.getInstance(currentAccount).checkIfFolderEmpty(folderId); + getMessagesController().checkIfFolderEmpty(folderId); }; if (undoView[0] != null) { getUndoView().showWithAction(dialogId, UndoView.ACTION_DELETE, deleteRunnable); @@ -5725,7 +5746,7 @@ public void didReceivedNotification(int id, int account, Object... args) { int channelId = (int) args[1]; searchViewPager.messagesDeleted(channelId, markAsDeletedMessages); } - } else if (id == NotificationCenter.didDatabaseCleared) { + } else if (id == NotificationCenter.didClearDatabase) { for (int a = 0; a < viewPages.length; a++) { viewPages[a].dialogsAdapter.didDatabaseCleared(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java index 75dd7824f86..b38e7082e0d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java @@ -253,7 +253,7 @@ public CharSequence getSubtitleFor(int i) { public final LinearLayoutManager layoutManager; private final FlickerLoadingView loadingView; private boolean firstLoading = true; - int animationIndex = -1; + private int animationIndex = -1; public int keyboardHeight; private final ChatActionCell floatingDateView; @@ -768,7 +768,6 @@ public boolean onPreDraw() { @Override public void onAnimationEnd(Animator animation) { NotificationCenter.getInstance(currentAccount).onAnimationFinish(animationIndex); - super.onAnimationEnd(animation); } }); animationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(animationIndex, null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java index 7aa38b9dd86..33f3cd92735 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java @@ -115,7 +115,7 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen private SparseArray ignoreUsers; - private int maxCount = MessagesController.getInstance(currentAccount).maxMegagroupCount; + private int maxCount = getMessagesController().maxMegagroupCount; private int chatType = ChatObject.CHAT_TYPE_CHAT; private boolean isAlwaysShare; private boolean isNeverShare; @@ -239,11 +239,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { currentAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - NotificationCenter.getInstance(currentAccount).onAnimationFinish(animationIndex); + getNotificationCenter().onAnimationFinish(animationIndex); requestLayout(); } }); - animationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(animationIndex, null); + animationIndex = getNotificationCenter().setAnimationInProgress(animationIndex, null); currentAnimation.start(); animationStarted = true; } else { @@ -349,24 +349,24 @@ public GroupCreateActivity(Bundle args) { if (isAlwaysShare || isNeverShare || addToGroup) { maxCount = 0; } else { - maxCount = chatType == ChatObject.CHAT_TYPE_CHAT ? MessagesController.getInstance(currentAccount).maxMegagroupCount : MessagesController.getInstance(currentAccount).maxBroadcastCount; + maxCount = chatType == ChatObject.CHAT_TYPE_CHAT ? getMessagesController().maxMegagroupCount : getMessagesController().maxBroadcastCount; } } @Override public boolean onFragmentCreate() { - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.contactsDidLoad); - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.updateInterfaces); - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatDidCreated); + getNotificationCenter().addObserver(this, NotificationCenter.contactsDidLoad); + getNotificationCenter().addObserver(this, NotificationCenter.updateInterfaces); + getNotificationCenter().addObserver(this, NotificationCenter.chatDidCreated); return super.onFragmentCreate(); } @Override public void onFragmentDestroy() { super.onFragmentDestroy(); - NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.contactsDidLoad); - NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.updateInterfaces); - NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatDidCreated); + getNotificationCenter().removeObserver(this, NotificationCenter.contactsDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.updateInterfaces); + getNotificationCenter().removeObserver(this, NotificationCenter.chatDidCreated); } @Override @@ -698,7 +698,7 @@ public void afterTextChanged(Editable editable) { if (maxCount != 0 && selectedContacts.size() == maxCount) { return; } - if (chatType == ChatObject.CHAT_TYPE_CHAT && selectedContacts.size() == MessagesController.getInstance(currentAccount).maxGroupCount) { + if (chatType == ChatObject.CHAT_TYPE_CHAT && selectedContacts.size() == getMessagesController().maxGroupCount) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("SoftUserLimitAlert", R.string.SoftUserLimitAlert)); @@ -718,7 +718,7 @@ public void afterTextChanged(Editable editable) { return; } if (channelId != 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(channelId); + TLRPC.Chat chat = getMessagesController().getChat(channelId); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); if (ChatObject.canAddAdmins(chat)) { builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); @@ -738,10 +738,10 @@ public void afterTextChanged(Editable editable) { return; } } - MessagesController.getInstance(currentAccount).putUser(user, !searching); + getMessagesController().putUser(user, !searching); } else { TLRPC.Chat chat = (TLRPC.Chat) object; - MessagesController.getInstance(currentAccount).putChat(chat, !searching); + getMessagesController().putChat(chat, !searching); } GroupCreateSpan span = new GroupCreateSpan(editText.getContext(), object); spansContainer.addSpan(span); @@ -1024,13 +1024,13 @@ private boolean onDonePressed(boolean alert) { if (chatType == ChatObject.CHAT_TYPE_CHANNEL) { ArrayList result = new ArrayList<>(); for (int a = 0; a < selectedContacts.size(); a++) { - TLRPC.InputUser user = MessagesController.getInstance(currentAccount).getInputUser(MessagesController.getInstance(currentAccount).getUser(selectedContacts.keyAt(a))); + TLRPC.InputUser user = getMessagesController().getInputUser(getMessagesController().getUser(selectedContacts.keyAt(a))); if (user != null) { result.add(user); } } - MessagesController.getInstance(currentAccount).addUsersToChannel(chatId, result, null); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); + getMessagesController().addUsersToChannel(chatId, result, null); + getNotificationCenter().postNotificationName(NotificationCenter.closeChats); Bundle args2 = new Bundle(); args2.putInt("chat_id", chatId); presentFragment(new ChatActivity(args2), true); @@ -1151,9 +1151,9 @@ public void notifyDataSetChanged() { public GroupCreateAdapter(Context ctx) { context = ctx; - ArrayList arrayList = ContactsController.getInstance(currentAccount).contacts; + ArrayList arrayList = getContactsController().contacts; for (int a = 0; a < arrayList.size(); a++) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(arrayList.get(a).user_id); + TLRPC.User user = getMessagesController().getUser(arrayList.get(a).user_id); if (user == null || user.self || user.deleted) { continue; } @@ -1260,10 +1260,10 @@ public int getItemCount() { count = contacts.size(); if (addToGroup) { if (chatId != 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chatId); + TLRPC.Chat chat = getMessagesController().getChat(chatId); inviteViaLink = ChatObject.canUserDoAdminAction(chat, ChatObject.ACTION_INVITE) ? 1 : 0; } else if (channelId != 0) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(channelId); + TLRPC.Chat chat = getMessagesController().getChat(channelId); inviteViaLink = ChatObject.canUserDoAdminAction(chat, ChatObject.ACTION_INVITE) && TextUtils.isEmpty(chat.username) ? 2 : 0; } else { inviteViaLink = 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java index d0995d98630..49aecd792eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java @@ -157,7 +157,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - doneItem = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneItem = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); progressView = new ContextProgressView(context, 1); progressView.setAlpha(0.0f); progressView.setScaleX(0.1f); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index ff3b39ef1b3..83fa5294a3e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -3410,7 +3410,9 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 105) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ApplicationLoader.canDrawOverlays = Settings.canDrawOverlays(this)) { - GroupCallActivity.groupCallInstance.dismissInternal(); + if (GroupCallActivity.groupCallInstance != null) { + GroupCallActivity.groupCallInstance.dismissInternal(); + } AndroidUtilities.runOnUIThread(() -> { GroupCallPip.clearForce(); GroupCallPip.updateVisibility(LaunchActivity.this); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index 03fc1113d6c..0d163880ef5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -1845,11 +1845,11 @@ private void createCircle(int meters) { circleOptions.center(new LatLng(myLocation.getLatitude(), myLocation.getLongitude())); circleOptions.radius(meters); if (isActiveThemeDark()) { - circleOptions.strokeColor(0xffffffff); - circleOptions.fillColor(0x20ffffff); + circleOptions.strokeColor(0x9666A3D7); + circleOptions.fillColor(0x1c66A3D7); } else { - circleOptions.strokeColor(0xff000000); - circleOptions.fillColor(0x20000000); + circleOptions.strokeColor(0x964286F5); + circleOptions.fillColor(0x1c4286F5); } circleOptions.strokePattern(PATTERN_POLYGON_ALPHA); circleOptions.strokeWidth(2); @@ -2704,7 +2704,7 @@ public ArrayList getThemeDescriptions() { themeDescriptions.add(new ThemeDescription(searchListView, 0, new Class[]{LocationCell.class}, new String[]{"addressTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{SharingLiveLocationCell.class}, new String[]{"nameTextView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{SharingLiveLocationCell.class}, new String[]{"distanceTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText2)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{SharingLiveLocationCell.class}, new String[]{"distanceTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{LocationLoadingCell.class}, new String[]{"progressBar"}, null, null, null, Theme.key_progressCircle)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{LocationLoadingCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText3)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java index 6173a75ba77..74d9e11b3e9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java @@ -154,7 +154,7 @@ public void onItemClick(int id) { if (type != 0) { ActionBarMenu menu = actionBar.createMenu(); - menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); titleTextView = new TextView(context); titleTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java index c7af7c08126..9568906aac0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PassportActivity.java @@ -1288,7 +1288,7 @@ public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean if (currentActivityType != TYPE_REQUEST && currentActivityType != TYPE_MANAGE) { ActionBarMenu menu = actionBar.createMenu(); - doneItem = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneItem = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); progressView = new ContextProgressView(context, 1); progressView.setAlpha(0.0f); progressView.setScaleX(0.1f); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java index 930c362506d..bbd0b514f9e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java @@ -483,7 +483,7 @@ public void onItemClick(int id) { ActionBarMenu menu = actionBar.createMenu(); if (currentStep == 0 || currentStep == 1 || currentStep == 2 || currentStep == 3 || currentStep == 4 || currentStep == 6) { - doneItem = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneItem = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); progressView = new ContextProgressView(context, 1); progressView.setAlpha(0.0f); progressView.setScaleX(0.1f); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java index b65943a6588..1f5e52d7c3c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java @@ -444,7 +444,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); fragmentView = view = new PhotoCropView(context); ((PhotoCropView) fragmentView).freeform = getArguments().getBoolean("freeform", false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 50b84d57b18..09cf6c325f1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -1724,7 +1724,9 @@ private class FrameLayoutDrawer extends SizeNotifierFrameLayoutPhoto { @Override protected void onPanTranslationUpdate(float y, float progress, boolean keyboardVisible) { currentPanTranslationY = y; - actionBar.setTranslationY(y); + if (currentEditMode != 3) { + actionBar.setTranslationY(y); + } if (miniProgressView != null) { miniProgressView.setTranslationY(y); } @@ -2916,7 +2918,6 @@ public void didReceivedNotification(int id, int account, Object... args) { for (int a = 0; a < arr.size(); a++) { MessageObject message = arr.get(a); if (imagesByIdsTemp[loadIndex].indexOfKey(message.getId()) < 0) { - FileLog.d("add message " + message.getId() + " media = " + message.messageOwner.media); imagesByIdsTemp[loadIndex].put(message.getId(), message); if (opennedFromMedia) { imagesArrTemp.add(message); @@ -8128,6 +8129,13 @@ protected void didSetAnimatedSticker(RLottieDrawable drawable) { } drawable.setProgressMs(videoPlayer.getCurrentPosition() - (startTime > 0 ? startTime / 1000 : 0)); } + + @Override + protected void onTextAdd() { + if (!windowView.isFocusable()) { + makeFocusable(); + } + } }; containerView.addView(photoPaintView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); photoPaintView.getDoneTextView().setOnClickListener(v -> { @@ -11380,11 +11388,12 @@ public boolean onPreDraw() { } animatorSet.playTogether(animators); animatorSet.setDuration(200); + int account = currentAccount; animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { AndroidUtilities.runOnUIThread(() -> { - NotificationCenter.getInstance(currentAccount).onAnimationFinish(transitionIndex); + NotificationCenter.getInstance(account).onAnimationFinish(transitionIndex); if (animationEndRunnable != null) { animationEndRunnable.run(); animationEndRunnable = null; @@ -11399,7 +11408,7 @@ public void onAnimationEnd(Animator animation) { setCaptionHwLayerEnabled(false); transitionAnimationStartTime = System.currentTimeMillis(); AndroidUtilities.runOnUIThread(() -> { - transitionIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(transitionIndex, new int[]{NotificationCenter.dialogsNeedReload, NotificationCenter.closeChats, NotificationCenter.mediaCountDidLoad, NotificationCenter.mediaDidLoad, NotificationCenter.dialogPhotosLoaded}); + transitionIndex = NotificationCenter.getInstance(account).setAnimationInProgress(transitionIndex, new int[]{NotificationCenter.dialogsNeedReload, NotificationCenter.closeChats, NotificationCenter.mediaCountDidLoad, NotificationCenter.mediaDidLoad, NotificationCenter.dialogPhotosLoaded}); animatorSet.start(); }); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java index 79ee180a4f8..9f9664ed479 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java @@ -326,7 +326,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); boolean hasChanges = hasChanges(); doneButton.setAlpha(hasChanges ? 1.0f : 0.0f); doneButton.setScaleX(hasChanges ? 1.0f : 0.0f); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 58c2bf68f24..9d7be199348 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -59,6 +59,7 @@ import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.WindowManager; +import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.EditText; @@ -2045,27 +2046,25 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } int currentPaddingTop = listView.getPaddingTop(); View view = null; + int pos = RecyclerView.NO_POSITION; for (int i = 0; i < listView.getChildCount(); i++) { - if (listView.getChildAdapterPosition(listView.getChildAt(i)) == 0) { + int p = listView.getChildAdapterPosition(listView.getChildAt(i)); + if (p != RecyclerView.NO_POSITION) { view = listView.getChildAt(i); + pos = p; break; } } - int pos = RecyclerView.NO_POSITION; + int top = 0; if (view != null) { - RecyclerView.ViewHolder holder = listView.findContainingViewHolder(view); - pos = holder.getAdapterPosition(); - if (pos == RecyclerView.NO_POSITION) { - pos = holder.getPosition(); - } top = view.getTop(); } boolean layout = false; if (actionBar.isSearchFieldVisible()) { layoutManager.scrollToPositionWithOffset(sharedMediaRow, -paddingTop); layout = true; - } else if ((!changed || !allowPullingDown) && pos != RecyclerView.NO_POSITION) { + } else if ((!changed || !allowPullingDown) && view != null) { layoutManager.scrollToPositionWithOffset(pos, top - paddingTop); layout = true; } @@ -2278,12 +2277,12 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { int animationIndex = -1; int account; - - @Override - protected void onAllAnimationsDone() { - super.onAllAnimationsDone(); - NotificationCenter.getInstance(account = currentAccount).onAnimationFinish(animationIndex); - } +// +// @Override +// protected void onAllAnimationsDone() { +// super.onAllAnimationsDone(); +// getNotificationCenter().onAnimationFinish(animationIndex); +// } @Override public void runPendingAnimations() { @@ -2296,7 +2295,7 @@ public void runPendingAnimations() { valueAnimator.addUpdateListener(valueAnimator1 -> listView.invalidate()); valueAnimator.setDuration(getMoveDuration()); valueAnimator.start(); - animationIndex = NotificationCenter.getInstance(account = currentAccount).setAnimationInProgress(animationIndex, null); + //animationIndex = getNotificationCenter().setAnimationInProgress(animationIndex, null); } super.runPendingAnimations(); } @@ -2794,7 +2793,21 @@ public void didChangeOwner(TLRPC.User user) { avatarContainer.setPivotY(0); frameLayout.addView(avatarContainer, LayoutHelper.createFrame(42, 42, Gravity.TOP | Gravity.LEFT, 64, 0, 0, 0)); - avatarImage = new AvatarImageView(context); + avatarImage = new AvatarImageView(context) { + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + if (getImageReceiver().hasNotThumb()) { + info.setText(LocaleController.getString("AccDescrProfilePicture", R.string.AccDescrProfilePicture)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + info.addAction(new AccessibilityNodeInfo.AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, LocaleController.getString("Open", R.string.Open))); + info.addAction(new AccessibilityNodeInfo.AccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK, LocaleController.getString("AccDescrOpenInPhotoViewer", R.string.AccDescrOpenInPhotoViewer))); + } + } else { + info.setVisibleToUser(false); + } + } + }; avatarImage.setRoundRadius(AndroidUtilities.dp(21)); avatarImage.setPivotX(0); avatarImage.setPivotY(0); @@ -2833,7 +2846,6 @@ public void didChangeOwner(TLRPC.User user) { openAvatar(); return false; }); - avatarImage.setContentDescription(LocaleController.getString("AccDescrProfilePicture", R.string.AccDescrProfilePicture)); avatarProgressView = new RadialProgressView(context) { private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -4432,6 +4444,7 @@ public void onResume() { } invalidateIsInLandscapeMode(); if (listAdapter != null) { + saveScrollPosition(); listAdapter.notifyDataSetChanged(); } @@ -6641,6 +6654,16 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { position == faqRow || position == policyRow || position == sendLogsRow || position == clearLogsRow || position == switchBackendRow || position == setAvatarRow; } + if (holder.itemView instanceof UserCell) { + UserCell userCell = (UserCell) holder.itemView; + Object object = userCell.getCurrentObject(); + if (object instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) object; + if (UserObject.isUserSelf(user)) { + return false; + } + } + } int type = holder.getItemViewType(); return type != 1 && type != 5 && type != 7 && type != 9 && type != 10 && type != 11 && type != 12 && type != 13; } @@ -7412,6 +7435,10 @@ public void updateListAnimated() { updateRowsIds(); diffCallback.fillPositions(diffCallback.newPositionToItem); DiffUtil.calculateDiff(diffCallback).dispatchUpdatesTo(listAdapter); + saveScrollPosition(); + } + + private void saveScrollPosition() { if (listView != null && layoutManager != null && listView.getChildCount() > 0) { View view = null; int position = -1; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ReportOtherActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ReportOtherActivity.java index 856d10848b4..33968c9365d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ReportOtherActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ReportOtherActivity.java @@ -97,7 +97,7 @@ public void onItemClick(int id) { }); ActionBarMenu menu = actionBar.createMenu(); - doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); LinearLayout linearLayout = new LinearLayout(context); fragmentView = linearLayout; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java index e0c04672e86..5e3d407a134 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java @@ -173,7 +173,7 @@ public void onItemClick(int id) { frameLayout.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); ActionBarMenu menu = actionBar.createMenu(); - doneItem = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneItem = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56), LocaleController.getString("Done", R.string.Done)); scrollView = new ScrollView(context); scrollView.setFillViewport(true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java index a1116673d58..c74c472e145 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java @@ -35,6 +35,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityNodeInfo; import android.view.inputmethod.EditorInfo; import android.widget.FrameLayout; import android.widget.ImageView; @@ -767,9 +768,17 @@ public boolean onActionItemClicked(ActionMode mode, MenuItem item) { } }); - showPasswordButton = new ImageView(context); + showPasswordButton = new ImageView(context) { + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setCheckable(true); + info.setChecked(passwordEditText.getTransformationMethod() == null); + } + }; showPasswordButton.setImageResource(R.drawable.msg_message); showPasswordButton.setScaleType(ImageView.ScaleType.CENTER); + showPasswordButton.setContentDescription(LocaleController.getString("TwoStepVerificationShowPassword", R.string.TwoStepVerificationShowPassword)); if (Build.VERSION.SDK_INT >= 21) { showPasswordButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector))); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java index 056d6b5ced4..74a896a8da5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VoIPFragment.java @@ -1814,7 +1814,6 @@ public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues sta } private void setMicrohoneAction(VoIPToggleButton bottomButton, VoIPService service, boolean animated) { - bottomButton.setCheckable(false); if (service.isMicMute()) { bottomButton.setData(R.drawable.calls_unmute, Color.BLACK, Color.WHITE, LocaleController.getString("VoipUnmute", R.string.VoipUnmute), true, animated); } else { @@ -1873,12 +1872,10 @@ private void setVideoAction(VoIPToggleButton bottomButton, VoIPService service, } } }); - bottomButton.setCheckable(false); bottomButton.setEnabled(true); } else { bottomButton.setData(R.drawable.calls_video, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.5f)), ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.12f)), "Video", false, animated); bottomButton.setOnClickListener(null); - bottomButton.setCheckable(false); bottomButton.setEnabled(false); } } @@ -1920,7 +1917,6 @@ private void setSpeakerPhoneAction(VoIPToggleButton bottomButton, VoIPService se } private void setFrontalCameraAction(VoIPToggleButton bottomButton, VoIPService service, boolean animated) { - bottomButton.setCheckable(false); if (!currentUserIsVideo) { bottomButton.setData(R.drawable.calls_flip, ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.5f)), ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.12f)), LocaleController.getString("VoipFlip", R.string.VoipFlip), false, animated); bottomButton.setOnClickListener(null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java index 3156affef9e..9cecb84c7e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java @@ -532,8 +532,8 @@ public void onCaptionCleared() { selectedMessagesCountTextView.setOnTouchListener((v, event) -> true); actionMode.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 65, 0, 0, 0)); - actionModeViews.add(actionMode.addItemWithWidth(forward, R.drawable.msg_forward, AndroidUtilities.dp(54))); - actionModeViews.add(actionMode.addItemWithWidth(delete, R.drawable.msg_delete, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItemWithWidth(forward, R.drawable.msg_forward, AndroidUtilities.dp(54), LocaleController.getString("Forward", R.string.Forward))); + actionModeViews.add(actionMode.addItemWithWidth(delete, R.drawable.msg_delete, AndroidUtilities.dp(54), LocaleController.getString("Delete", R.string.Delete))); selectedWallPapers.clear(); } diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index 78f35644211..978a9b73b92 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -41,7 +41,7 @@ إعادة تعيين الحساب نظرًا لأن الحساب **%1$s** نشطٌ ومحميٌ بكلمة مرور؛ سنقوم بحذفه خلال أسبوع لدواعٍ أمنية.\n\nيمْكنك إلغاء هذه العملية في أي وقت. ستتمكن من إعادة تعيين حسابك خلال: - تم إلغاء محاولاتك السابقة لإعادة تعيين هذا الحساب. فضلًا أعد المحاولة بعد 7 أيام. + محاولاتك الأخيرة لإعادة تعيين هذا الحساب قد أُلغيت من قبل مُستخدمه النشط. رجاءً، أعد المحاولة خلال سبعة أيام. إعادة تعيين رابط غير صحيح أو منتهي الصلاحية. تم إلغاء عملية حذف حسابك %1$s. يمكنك الآن إغلاق هذه النافذة. @@ -165,6 +165,7 @@ تثبيت إلغاء التثبيت أرشفة + الأرشيف إلغاء الأرشفة المحادثات المؤرشفة حذف المحادثة @@ -172,7 +173,7 @@ اختر محادثة تحويل إلى... صورة سرية - مقطع مرئي سري + "مقطع مرئي يختفي " صورة متحركة سرية يستخدم %1$s إصدارًا قديمًا من تيليجرام، لذلك ستظهر الصور السرية في الوضع التوافقي.\n\nعندما يقوم %2$s بتحديث تيليجرام فإن الصور التي بها عداد تدمير خلال دقيقة أو أقل ستعمل بطريقة «الاستمرار بالضغط للمشاهدة»، وسيتم إخبارك عندما يلتقط المستقبل صورة للشاشة. الرسائل @@ -181,7 +182,7 @@ كتم لمدة %1$s إلغاء الكتم خلال %1$s - كتم للأبد + تعطيل الوُسُوم الأخيرة الأشخاص @@ -214,7 +215,7 @@ عادي يحتاج **تيليجرام** إلى الوصول لجهات اتصالك لكي تتمكن من التواصل مع أصدقائك عبر جميع أجهزتك، ستتم مزامنة جهات اتصالك باستمرار مع خوادم تيليجرام السحابية شديدة التشفير. ليس الآن - الاستمرار + استمرار جهات اتصالك في تيليجرام هذا هو أرشيفك سيتم إلغاء أرشفة المحادثات غير المكتومة عند وصول رسائل جديدة إليها. @@ -229,7 +230,7 @@ عرض الملف الشخصي فتح القناة فتح المجموعة - إرسال رسالة + رسالة خاصّة إشارة تم كتم الإشعارات الإشعارات مكتومة لـ %1$s @@ -267,7 +268,7 @@ هل ترغب حقًا في مغادرة **%1$s**؟ المعذرة، لا يمكنك إضافة هذا المستخدم للمجموعات. المعذرة، المجموعة ممتلئة. - عذرًا، إذا لم يعد شخص جزءًا من مجموعة؛ يجب أن تكون في جهات اتصاله في تيليجرام لإضافته مرة أخرى إليها.\n\nلاحظ أنه لا يزال بإمكان هذا الشخص الانضمام عبر رابط دعوة المجموعة طالما أنه ليس في قائمة المستخدمين الذين تمت إزالتهم. + عذرًا، إذا لم يعد شخص جزءًا من مجموعة؛ يجب أن تكون في جهات اتصاله في تيليجرام لإضافته مرة أخرى.\n\nلاحظ أنه لا يزال بإمكان هذا الشخص الانضمام عبر رابط دعوة المجموعة طالما أنه ليس في قائمة «مستخدمون تمت إزالتهم». المعذرة، يوجد الكثير من المشرفين في هذه المجموعة. المعذرة، يملك هذا المستخدم الكثير من المجموعات أو القنوات العامة. دعه يجعل بعض مجموعاته أو قنواته الحالية خاصة أولًا. المعذرة، يملك هذا المستخدم الكثير من المجموعات المحلية. دعه يحذف أو ينقل ملكية بعض منها أولًا. @@ -295,7 +296,7 @@ لن يتمكن المستخدمون الذين أزالهم المشرفون من القناة من الانضمام إليها حتى عبر روابط الدعوة الخاصة. قناة جديدة اسم القناة - إضافة جهات اتصالك لقناتك + إضافة مشتركين لقناتك إذا قمت بتعيين رابط عام دائم للقناة فسيتمكن الآخرون من العثور عليها والانضمامِ إليها عبره.\n\nيمكنك استخدام الأحرف الإنجليزية والشَّرطاتِ السفلية.\n\nالحد الأدنى هو خمسُ خانات. إذا قمت بتعيين رابط عام دائم للمجموعة فسيتمكن الآخرون من العثور عليها والانضمامِ إليها عبره.\n\nيمكنك استخدام الأحرف الإنجليزية والشَّرطاتِ السفلية.\n\nالحد الأدنى هو خمسُ خانات. تحذير @@ -338,7 +339,7 @@ أسماء المجموعات لا يمكن أن تبدأ برقم. يتم التحقق من الاسم... %1$s متاح. - أعضاء + الأعضاء إضافة للمجموعة إضافة للقناة حذف من هذه القائمة @@ -371,16 +372,16 @@ تم تغيير المقطع المرئي للقناة تمت إزالة صورة القناة تم تغيير اسم القناة إلى un2 - المعذرة، لقد قمت بحجز أسماء مستخدمين كثيرة. يمكنك تعطيل بعض روابط مجموعاتك وقنواتك القديمة, أو قم بإنشاء واحدة خاصة عوضًا عن ذلك. + لقد قمت بحجز روابط عامة كثيرة. يمكنك استبدال رابط مجموعة أو قناة قديمة، أو قم بإنشاء واحدة خاصة عوضًا عن ذلك. المالك مشرف مشرف كتم إلغاء الكتم إضافة مشرف - إزالة مستخدم + حظر مستخدم إلغاء الحظر - اضغط باستمرار على المستخدم لرفع الحظر عنه + اضغط باستمرار على المستخدم لإلغاء حظره الدعوة عبر رابط خاص إزالة المشرف تعديل الصلاحيات @@ -397,7 +398,7 @@ المعذرة، لا يمكنك إضافة هذا المستخدم للقنوات. المعذرة، يوجد الكثير من المشرفين في هذه القناة. عذرًا، يوجد الكثير من البوتات في هذه القناة. - المعذرة، يمكنك إضافة أول 200 عضو فقط إلى القناة. يمكن لعدد غير محدود من الناس الانضمام عبر رابط القناة. + المعذرة، يمكنك إضافة أول 200 مشترك فقط إلى القناة. يمكن لعدد غير محدود من الناس الانضمام عبر رابط القناة. الكثير من المُجتمعات المعذرة، أنت عضو في الكثير من المجموعات والقنوات. الرجاء مغادرة بعض منها قبل إنشاء واحدة جديدة. المعذرة، أنت عضو في الكثير من المجموعات والقنوات. الرجاء مغادرة بعض منها قبل الانضمام لواحدة جديدة. @@ -531,7 +532,7 @@ البحث في الويب الإحصائيات يمكن إضافة البوتات كمشرفين فقط. - المعذرة، يمكن إضافة البوتات للقنوات كمشرفين فقط. + يمكن إضافة البوتات للقنوات كمشرفين فقط. تعيينُه كمشرف سيتم إزالة %1$s من المشرفين إذا قمت بتقييده. المناقشات @@ -541,7 +542,7 @@ حدد المجموعة التي ستستضيف التعليقات من قناتك. سيتم تحويل جميع منشورات القناة الجديدة إلى هذه المجموعة. تم تحديد **%1$s** على أنها المجموعة التي سيتم استخدامها لاستضافة التعليقات لقناتك. - تم ربط هذه المجموعة بـ **%1$s** على أنها منصة نقاشاتها. + تم ربط هذه المجموعة كمنصة نقاشات لـ %1$s. سيتم تحويل جميع المنشورات الجديدة في هذه القناة للمجموعة. إنشاء مجموعة جديدة إلغاء ربط المجموعة @@ -566,7 +567,8 @@ تم تفعيل الوضع البطيء. لا يمكنك إرسال أكثر من رسالة مرةً واحدة. تم تفعيل الوضع البطيء. لا يمكنك تحديد المزيد من العناصر. المعذرة، هذا النص طويل للغاية ولا يمكن إرساله برسالة واحدة.\n\nتم تفعيل الوضع البطيء. لا يمكنك إرسال عدة رسائل مرةً واحدة. - **%1$s** promoted to admin + تمت ترقية **%1$s** للإشراف + تمت إزالة **%1$s** من **%2$s** استفتاء جديد اختبار جديد @@ -646,7 +648,7 @@ **لم يتم العثور على أحداث**\n\nلا توجد نتائج تطابق ما بحثت عنه\nضمن الأحداث الأخيرة. لم يتم العثور على أحداث أخيرة تحوي «**%1$s**». ما هي آخر الأحداث؟ - هي قائمة تحوي جميع الأحداث التي قام بها أعضاء المجموعة ومشرفوها خلال آخِر 48 ساعة. + هذا سجل يحوي الأحداث المهمة التي قام بها أعضاء المجموعة ومشرفوها خلال آخِر ٤٨ ساعة. هو سجل يحوي جميع الإجراءات التي قام بها مشرفو القناة خلال آخر ٤٨ ساعة. غيَّر un1 اسم المجموعة إلى «%1$s» غيَّر un1 اسمَ القناة إلى «%1$s» @@ -716,15 +718,16 @@ تعديل الرسائل حذف الرسائل إضافة مشرفين - إرسال كمجهول + البقاء متخفيًا حظر المستخدمين + إدارة المحادثات الصوتية إضافة مستخدمين اللقب: %1$s اللقب تثبيت الرسائل كافة الأحداث استثناءات جديدة - حقوق الإشراف + ترقية الإشراف أعضاء جدد معلومات المجموعة معلومات القناة @@ -732,8 +735,15 @@ رسائل معدلة رسائل مثبتة الأعضاء المغادرون + المحادثات الصوتية عيّن un1 عداد الوضع البطيء ليصبح %1$s عطّل un1 الوضع البطيء + بدأ un1 محادثة صوتية + أنهى un1 المحادثة الصوتية + un1 كتم un2 في محادثة صوتية + ألغى un1 كتم un2 في محادثة صوتية + سمح un1 للمشاركين الجدد في المحادثة الصوتية بالتحدث + كتم un1 المشاركين الجدد في المحادثة الصوتية رسالة جماعية جديدة أدخل اسم القائمة @@ -762,7 +772,7 @@ لا يمكن أن يتجاوز حجم الملف %1$s الذاكرة غير موجودة نقل USB مفعَّل - الذاكرة الداخلية + التخزين الداخلي الذاكرة الخارجية جذر النظام بطاقة التخزين الخارجية @@ -810,8 +820,8 @@ %1$s يلعب لعبة... يرسل %1$s مقطعًا مرئيًا... يرسل %1$s ملفًا... - يسجل رسالةً صوتية... - يسجل رسالةً مرئية... + يسجل رسالة صوتية... + يسجل رسالة مرئية... يرسل ملفًا صوتيًا... يرسل صورة... يلعب لعبة... @@ -852,7 +862,7 @@ اسحب للإلغاء حفظ في الجهاز حفظ في الصور المتحركة - هل ترغب بحذف الصورة المتحركة؟ + إزالة الصورة المتحركة من هنا؟ حفظ في الجهاز مشاركة تطبيق ملف التعريب @@ -882,7 +892,7 @@ حظر %1$s حظر المستخدم تبليغ عن إزعاج ومغادرة - إضافة جهة اتصال + إضافة كجهة اتصال إضافة %1$s لجهات الاتصال عرض جهة الاتصال هل ترغب بحظر **%1$s** من مراسلتك والاتصال بك على تيليجرام؟ @@ -899,12 +909,12 @@ اضغط هنا للوصول للصور المتحركة المحفوظة تثبيت إشعار جميع الأعضاء - Also pin for %1$s + تثبيتها عندي وعند %1$s إلغاء التثبيت تثبيت الرسالة إلغاء تثبيت الرسالة - Do you want to pin an older message while leaving a more recent one pinned? - هل تريد تثبيت هذه الرسالة لكل الأعضاء في المجموعة؟ + "هل تريد تثبيت رسالة أقدم مع ترك أحدث رسالة مثبتة؟ " + تثبيت هذه الرسالة في المجموعة؟ هل ترغب في تثبيت هذه الرسالة في هذه القناة؟ هل ترغب في تثبيت هذه الرسالة أعلى هذه المحادثة؟ هل ترغب في إلغاء تثبيت هذه الرسالة؟ @@ -935,6 +945,13 @@ تعديل الرسالة تعديل الوصف انقر لتعديل الوسائط + تعديل هذه الصورة + تعديل هذا المقطع المرئي + استبدال الصورة + استبدال المقطع + استبدال الوسائط + استبدال الملف + استبدال الملف الصوتي مرِّر إلى الأسفل للبوتات %1$s المعذرة، انتهت مهلة تعديل الرسالة. @@ -1003,6 +1020,8 @@ انقر لأخذ صورة، اضغط باستمرار لتصوير مقطع مرئي انقر للعرض في قائمة. إرسال بدون صوت + إرسال كصورة جديدة + استبدال الصورة إرسال الآن إعادة جدولة اليوم @@ -1052,14 +1071,14 @@ نقل ملكية البوت سيتم نقل **جميع حقوق الملكية** للبوت إلى المستخدم المحدّد. تغيير المالك - تستطيع نقل البوت فقط إذا: + يمكنك نقل هذا البوت في حال كان لديك: كتابة تعليق التعليقات تعليق الردود ما من تعليقات هنا بعد... ما من ردود هنا بعد... - عرض في المحادثة + عرضه في المحادثة الإرسال متخفيًا بداية المناقشة عرض الموضوع @@ -1068,8 +1087,8 @@ المعذرة، تمت إزالة هذا المنشور من مجموعة المناقشة. إلغاء تثبيت كل الرسائل إخفاء الرسائل المثبّتة - Pinned messages hidden - Pinned messages will be shown again if a new message is pinned. + تم إخفاء الرسائل المثبّتة + ستظهر الرسائل المثبّتة مرة أخرى في حال تم تثبيت رسالة جديدة. عيّن %1$s عداد التدمير الذاتي ليصبح %2$s قمت بتعيين عداد التدمير الذاتي ليصبح %1$s @@ -1116,7 +1135,7 @@ أرسل %1$s ملفًا لمجموعة %2$s أرسل %1$s صورةً متحركة لمجموعة %2$s أرسل %1$s فاتورةً لمجموعة %2$s لقاء %3$s - أرسل %1$s رسالةً صوتيةً لمجموعة %2$s + أرسل %1$s رسالة صوتية إلى %2$s أرسل %1$s رسالةً مرئيةً لمجموعة %2$s أرسل %1$s ملفًا صوتيًا لمجموعة %2$s أرسل %1$s ملصقًا لمجموعة %2$s @@ -1126,6 +1145,10 @@ غيّرَ %1$s صورة مجموعة %2$s غيّر %1$s المقطع المرئي للمجموعة %2$s %1$s أضاف %3$s للمجموعة %2$s + %1$s دعا %3$s إلى محادثة صوتية في %2$s + دعاك %1$s إلى محادثة صوتية في %2$s + بدأ %1$s محادثة صوتية في %2$s + أنهى %1$s المحادثة الصوتية في المجموعة %2$s عاد %1$s لمجموعة %2$s انضم %1$s لمجموعة %2$s %1$s أزال %3$s من المجموعة %2$s @@ -1158,7 +1181,7 @@ ثبّتَ %1$s ملفًا في مجموعة %2$s ثبّتَ %1$s ملصقًا في مجموعة %2$s ثبّتَ %1$s ملصق %3$s في مجموعة %2$s - ثبّتَ %1$s رسالةً صوتيةً في مجموعة %2$s + ثبّتَ %1$s رسالة صوتية في %2$s ثبّتَ %1$s رسالةً مرئيةً في مجموعة %2$s ثبّتَ %1$s جهة اتصال %3$s في مجموعة %2$s ثبّتَ %1$s خريطةً في مجموعة %2$s @@ -1196,10 +1219,10 @@ ثبّت %1$s ملفًا ثبّت %1$s فاتورة ثبّت %1$s ملصقًا - %1$s pinned a %2$s sticker + ثبّت %1$s ملصق %2$s ثبّت %1$s رسالة صوتيّة ثبّت %1$s رسالة مرئية - %1$s pinned a contact %2$s + ثبّت %1$s جهة اتصال %2$s ثبّت %1$s خريطة ثبّت %1$s موقعًا مباشرًا ثبّت %1$s صورة متحركة @@ -1245,7 +1268,7 @@ اعثر على الأشخاص القريبين للتحدث معهم البحث عن أشخاص عبر اسم المستخدم جهة اتصال جديدة - رقم الهاتف **%1$s** ليس في قائمة جهات اتصالك. هل تريد إضافته؟ + رقم الهاتف **%1$s** ليس في جهات اتصالك. هل تريد إضافته؟ إضافة جهة اتصال إضافة أشخاص... @@ -1262,6 +1285,7 @@ انضمام تم نسخ الرابط للحافظة تم نسخ الرابط للحافظة.\nلن يعمل هذا الرابط إلا لأعضاء هذه المحادثة. + This link will only work for members of this chat. للأسف لا يمكنك الوصول إلى هذه الرسالة؛ أنت لست عضوًا في المحادثة التي تم نشرها فيها. تم نسخ رقم الهاتف للحافظة تم نسخ البريد للحافظة @@ -1279,12 +1303,12 @@ البحث عن أشخاص... البحث عن مستخدمين ومجموعات... - أعضاء + الأعضاء الوسائط المتبادلة الإعدادات "إضافة مشترك " إضافة عضو - تعيين المشرفين + إضافة مشرفين حظر من المجموعة مغادرة المجموعة وحذفها حذف ومغادرة المجموعة @@ -1296,7 +1320,7 @@ تحويل إلى مجموعة خارقة تحذير تحذير: هذا القرار لا يمكن التراجع عنه، لن تتمكن من إعادة المجموعة الخارقة إلى مجموع عادية مرة أخرى. - **تم بلوغ الحد الأقصى لعدد الأعضاء**\n\nلتخطي هذا الحد والحصول على خصائص جديدة، يمكنك الترقية لمجموعة خارقة:\n\n• يمكن أن تحتوي المجموعات الخارقة على %1$s عضو\n• يمكن للأعضاء الجدد مشاهدة محتوى المحادثة كاملًا\n• تختفي الرسائل المحذوفة من أجهزة جميع الأعضاء\n• يمكن للمشرفين إضافة وصفٍ للمجموعة\n• يمكن لمالك المجموعة إنشاء رابط عام لها + **تم بلوغ الحد الأقصى للأعضاء**\n\nلمزيد من المساحة والميزات الإضافية؛ قم بالترقية إلى مجموعة خارقة:\n\n • يمكن للمجموعات الخارقة استيعاب %1$s عضو\n • يمكن للأعضاء الجدد رؤية سجل المحادثات بالكامل\n • تختفي الرسائل المحذوفة لكل الأعضاء\n • يمكن للمشرفين إضافة وصف للمجموعة\n • يمكن للمالك إنشاء رابط عام للمجموعة ** في المجموعات الخارقة:**\n\n• يمكن للأعضاء الجدد مشاهدة محتوى المحادثة كاملًا\n• تختفي الرسائل المحذوفة من أجهزة جميع الأعضاء\n• يمكن للمشرفين إضافة وصفٍ للمجموعة\n• يمكن لمالك المجموعة إنشاء رابط عام لها **ملحوظة:** لا يمكنك التراجع عن هذا القرار. @@ -1366,8 +1390,8 @@ المعذرة، اسم المستخدم غير مقبول. يجب ألا يقل اسم المستخدم عن 5 حروف. لا يمكن أن يتخطى الاسم 32 حرفًا كحد أقصى. - عذرًا، لا يمكن لاسم المستخدم بأن يبدأ برقم. - يمكنك اختيار اسم مستخدم لحسابك في **تيليجرام**، إذا قمت بذلك سيتمكن المستخدمون الآخرون من العثور عليك والتواصل معك عبر هذا الاسم دون معرفة رقمك.\n\nيمكنك استخدام **الحروف والأرقام الإنجليزية** وكذلك الشَّرطة السفلية. الطول الأدنى هو **خمسُ خانات**. + لا يمكن لاسم المستخدم أن يبدأ برقم. + يمكنك اختيار اسم مستخدم في **تيليجرام**.\nإذا قمت بذلك سيتمكن الآخرون من العثور عليك باسم المستخدم والتواصل معك دون الحاجة لرقم هاتفك.\n\nيمكنك استخدام **الحروف والأرقام الإنجليزية** وكذلك الشَّرطة السفلية. الطول الأدنى هو **5 خانات**. يقوم هذا الرابط بفتح محادثة معك:\n%1$s يتم التحقق من اسم المستخدم... %1$s متاح. @@ -1392,7 +1416,7 @@ ملصقات المجموعة المزيد من الملصقات احذف من المفضلة - حذف من الأخيرة + إزالة من الأخيرة إضافة إلى الأقنعة لم يُعثر على الملصقات تمت إزالة الملصقات @@ -1435,7 +1459,7 @@ الأقنعة المؤرشفة ما من ملصقات مؤرشفة ما من أقنعة مؤرشفة - يمكنك الاحتفاظ بـ 200 حزمة ملصقات كحدٍ أقصى.\nستتم أرشفة الحزم غير المستخدمة عند إضافتك للمزيد. + يمكنك الاحتفاظ بـ ٢٠٠ حزمة ملصقات نشطة.\nستتم أرشفة الحزم غير المستخدمة عند إضافتك للمزيد. يمكنك الاحتفاظ بـ 200 حزمة أقنعة كحدٍ أقصى.\nستتم أرشفة الحزم غير المستخدمة عند إضافتك للمزيد. إرسال الملصق الملصقات المؤرشفة @@ -1728,7 +1752,7 @@ شارةُ عدّاد الرسائل مفعَّلة تضمين المحادثات المكتومة - عَدُّ الرسائل غير المقروءة + عدد الرسائل غير المقروءة قصير طويل تنزيل الوسائط تلقائيًا @@ -1814,6 +1838,10 @@ أصوات داخل المحادثات افتراضي افتراضي + الافتراضية + الافتراضية داخل التطبيق + %1$s داخل التطبيق + صامتة إشعارات ذكية الاستثناءات إضافة استثناء @@ -1960,7 +1988,7 @@ يتم الحساب... المستندات الصور - الرسائل الصوتية/المرئية + الرسائل الصوتية والمرئية المقاطع المرئية الصوتيات الصور المتحركة @@ -2030,7 +2058,7 @@ قم بإدخال رمز التأكيد الذي أرسلناه إلى %1$s. يرجى إدخال كلمة مرورك للوصول إلى بياناتك الشخصية. يطلب **%1$s** الوصول لبياناتك الشخصية لتسجيلك في خدماتهم. - يرجى إدخال كلمة مرورك في تيليجرام لفك تشفير بياناتك + أدخل كلمة مرورك في تيليجرام لفك تشفير بياناتك أنت توافق على سياسة خصوصية %1$s وتسمح لـ@%2$s بمراسلتك. أنت ترسل وثائقك إلى %1$s مباشرةً وتسمح لـ@%2$s بمراسلتك. السماح @@ -2160,7 +2188,7 @@ الفيتنامية الجلسات النشطة - الجلسة الحالية + هذا الجهاز ما من جلسات أخرى نشطة حاليًا يمكنك تسجيل الدخول لحسابك في تيليجرام عبر جوال، جهاز لوحي، أو جهاز حاسوب آخر باستخدام رقم الهاتف ذاته. سيقوم تيليجرام بمزامنة كافة بياناتك بشكل فوري. الجلسات النشطة @@ -2230,7 +2258,7 @@ البوتات يتم إضافة المحادثات يرجى الانتظار بضع لحظات ريثما نقوم بملء هذا المجلد لك... - ما من محادثات لعرضها + المجلد فارغ ما من محادثات تنتمي لهذا المجلد حاليًّا. مجلد جديد ما من محادثات @@ -2381,8 +2409,8 @@ تم تحديثه الآن أنت و%1$s %1$s تتم مشاركته مع %2$s - %1$s sharing with %2$s - %1$s sharing with %2$s + تتم مشاركة %1$s مع %2$s + أنت تشارك %1$s مع %2$s إيقاف الكل تقوم بمشاركة موقعك الحي مع %1$s اختر المدة التي سيتمكن خلالها %1$s من مشاهدة موقعك الفعلي. @@ -2413,17 +2441,17 @@ الأماكن في هذه المنطقة تنبيه الاقتراب نبّهني عندما يكون %1$s على بعد %2$s - Notify when someone is within %1$s + نبهني عندما يكون أي عضو على بعد %1$s أنت أقرب من %1$s مشاركة الموقع مشاركة لكي يعمل التنبيه؛ شارك موقعك المباشر في هذه المحادثة. التنبيه عندما يكون %1$s قريبًا التنبيه عندما يكون أعضاء المجموعة قريبين - Proximity alert set - We will notify you once %1$s is within %2$s from you. - We will notify you once someone is within %1$s from you. - Proximity alert cancelled + تنبيه الاقتراب يعمل + "سيتم تنبيهك بمجرد أن يكون %1$s على بعد %2$s منك. " + "سيت تنبيهك بمجرد أن يكون أي عضو على بعد %1$s منك. " + تم إلغاء التنبيه بالاقتراب عرض في لائحة عرض كمصفوفة @@ -2534,38 +2562,38 @@ تم حفظ الصورة في التنزيلات تم حفظ المقطع في التنزيلات تم حفظ الصورة المتحركة في التنزيلات - File saved to music - File saved to downloads - %1$d files saved to downloads - File saved to downloads - %1$d files saved to downloads - %1$d files saved to downloads - %1$d files saved to downloads - %1$d files saved to downloads - %1$d photos saved to gallery - Photo saved to gallery - %1$d photos saved to gallery - %1$d photos saved to gallery - %1$d photos saved to gallery - %1$d photos saved to gallery - %1$d videos saved to gallery - Video saved to gallery - %1$d videos saved to gallery - %1$d videos saved to gallery - %1$d videos saved to gallery - %1$d videos saved to gallery - %1$d files saved to music - File saved to music - %1$d files saved to music - %1$d files saved to music - %1$d files saved to music - %1$d files saved to music - %1$d items saved to gallery - One item saved to gallery - %1$d items saved to gallery - %1$d items saved to gallery - %1$d items saved to gallery - %1$d items saved to gallery + تم حفظ الملف في الموسيقى + تم حفظ الملف في التنزيلات + تم حفظ %1$d ملفات في التنزيلات + تم حفظ ملف في التنزيلات + تم حفظ ملفين في التنزيلات + تم حفظ %1$d ملفات في التنزيلات + تم حفظ ١١ ملفًا في التنزيلات + تم حفظ %1$d ملف في التنزيلات + تم حفظ %1$d صورة في المعرض + تم حفظ الصورة في المعرض + تم حفظ صورتين في المعرض + تم حفظ %1$d صور في المعرض + تم حفظ %1$d صورة في المعرض + تم حفظ %1$d صورة في المعرض + تم حفظ %1$d مقاطع في المعرض + تم حفظ المقطع المرئي في المعرض + تم حفظ مقطعين في المعرض + تم حفظ %1$dمقاطع مرئية في المعرض + تم حفظ %1$d مقطعًا مرئيًا في المعرض + تم حفظ %1$d مقطع مرئي في المعرض + تم حفظ %1$d ملفات صوتيّة + تم حفظ الملف الصوتيّ + تم حفظ ملفّين صوتيين + تم حفظ %1$d ملفات صوتيّة + تم حفظ %1$d ملفًا صوتيًا + تم حفظ %1$d ملف صوتي + تم حفظ %1$d عنصر في المعرض + تم حفظ عنصر واحد في المعرض + تم حفظ عنصرين في المعرض + تم حفظ %1$d عناصر في المعرض + تم حفظ %1$d عنصرًا في المعرض + تم حفظ %1$d عنصر في المعرض التحقق بخطوتين التحقق بخطوتين @@ -2574,6 +2602,7 @@ العودة للإعدادات العودة إلى جواز السفر تعيين كلمة المرور + Show password تعيين كلمة مرور إضافية يمكنك تعيين كلمة مرور إضافية يتم طلبها عند تسجيل الدخول من جهاز غير معروف، إضافةً إلى الرمز الذي يصلك في رسالة SMS قصيرة. كلمة مرورك @@ -2630,7 +2659,7 @@ رمز الاسترداد لقد قمنا بإرسال رمز الاسترداد إلى بريدك الإلكتروني الذي اخترته مسبقًا:\n\n%1$s يرجى تفقُّدُ بريدك وإدخال الرمز المرسَل إليك والمكون من 6 أرقام. - هل تواجه صعوبة في الوصول إلى بريدك %1$s؟ + غير قادر على فتح %1$s؟ هل تواجه مشكلة في الدخول إلى بريدك الإلكتروني؟ إذا لم تتمكن من الوصول إلى بريدك الإلكتروني فإن خياراتك المتبقية هي إما أن تتذكر كلمةَ مرورك، أو أن تعيد تعيين حسابك وتفقدَ جميعَ محتوياته. إعادة تعيين حسابي @@ -2654,6 +2683,7 @@ استخدام التخزين والشبكة استخدام التخزين استهلاك البيانات + مسار التخزين الخلوية Wi-Fi التجوال @@ -2676,8 +2706,8 @@ الخصوصية والأمان الخصوصية آخر ظهور ومتصل - الصورة الشخصية - من يمْكنه رؤية صورتي الشخصية؟ + الصور الشخصية + من يمْكنه رؤية صور ومقاطع ملفّي التعريفي؟ بإمكانك تخصيص من يمْكنه رؤية صورتك الشخصية بدقة انتقائية. يمكنك إضافة مستخدمين أو مجموعات بأكملها كاستثناءات ليتجاوزوا القيم في الأعلى. رقم الهاتف @@ -2734,7 +2764,7 @@ من يمْكنه رؤية آخر ظهور لك؟ إضافة استثناءات إضافة للاستثناءات - لن تتمكن من رؤية آخر ظهور للأشخاص الذين اخترت ألا يروا آخر ظهور لك. سيتم بدلًا من ذلك عرض آخر ظهور تقريبي (شُوهدَ مؤخرًا، خلال أسبوع، خلال شهر). + لن ترى آخر ظهور أو حالة الاتصال للأشخاص الذين اخترت ألا يروا آخر ظهور لك. سيتم بدل من ذلك عرض آخر ظهور تقريبي (قريبا، خلال أسبوع، خلال شهر). لقد قمت بتغيير بعض إعدادات الخصوصية؛ تطبيق التغييرات؟ المشاركة دائمًا مع عدم المشاركة مع @@ -2806,7 +2836,7 @@ حسنًا إيقاف الانتظار أكثر - الاستمرار + استمرار إنشاء رابط قطع تحديث التطبيق @@ -2837,7 +2867,7 @@ لقد قمت بإضافة un2 قمت بإحراز %1$s أحرز un1 %1$s - قمت بإحراز %1$s في un2 + أحرزت %1$s في un2 un1 أحرز %1$s في un2 لقد أزلتَ صورة المجموعة لقد غيّرتَ صورة المجموعة @@ -2852,6 +2882,14 @@ un1 الآن على بعد %1$s منك أنت الآن على بعد %1$s من un1 un1 الآن على بعد %1$s منك un2 + دعاك un1 إلى هذه المجموعة + دعاك un1 إلى هذه القناة + بدأ un1 محادثة صوتية + "أنت بدأت محادثة صوتية " + انتهت المحادثة الصوتية (%s) + "قام un1 بدعوة un2 إلى المحادثة الصوتية " + قمت بدعوة un2 إلى المحادثة الصوتية + دعاك un1 إلى المحادثة الصوتية لقد سمحت لهذا البوت بمراسلتك عندما سجّلت دخولك إلى %1$s استلم %1$s الوثائق التالية: %2$s التفاصيل الشخصية @@ -2867,7 +2905,7 @@ عقد الإيجار رقم الهاتف بريد إلكتروني - نسختك الحالية من تيليجرام لا تدعم هذه الرسالة؛ رجاء قم بتحديث التطبيق: https://telegram.org/update + نسخة تيليجرام التي لديك لاتدعم هذه الرسالة. حدّث التطبيق لعرضها: https://telegram.org/update صورة مقطع مرئي صورة ذاتية التدمير @@ -2908,9 +2946,9 @@ يرجى تسجيل الدخول إلى حسابك في تيليجرام لتتمكن من استخدام جواز تيليجرام. تم حظر هذا الرقم. انتهت صلاحية الرمز، يرجى إعادة محاولة تسجيل الدخول. - محاولات كثيرة خاطئة، نرجو المحاولة لاحقًا + محاولات كثيرة خاطئة، نرجو المحاولة لاحقًا. محاولات كثيرة، يرجى إعادة المحاولة خلال %1$s - الرمز غير صحيح + الرمز غير صحيح، حاول لاحقًا. المعذرة، لقد قمت بحذف حسابك وإعادة إنشائه عدة مرات مؤخرًا، انتظر لعدة أيام رجاءً قبل محاولة إنشاء الحساب من جديد. الاسم الأول غير صحيح المعذرة، لا يمكن استخدام اسم العائلة هذا. @@ -2933,7 +2971,7 @@ هل ترغب في إرسال هذه الرسالة إلى **%1$s**؟ هل ترغب في إرسال هذه اللعبة إلى **%1$s**؟ هل ترغب في إرسال جهة الاتصال هذه إلى **%1$s**؟ - هل ترغب حقًا في تسجيل الخروج؟\n\nتذكَّر أنه يمكنك استخدام تيليجرام على جميع أجهزتك في ذات الوقت بسهولة تامة.\n\nولا تنسَ أن تسجيل الخروج سيحذف كل محادثاتك السرية. + هل ترغب حقًا في تسجيل الخروج؟\n\nاعلم أنه يمكنك استخدام تيليجرام على أجهزتك المتعددة بسلاسة وفي نفس الوقت.\n\nتذكر أن تسجيل الخروج يحذف كل محادثاتك السرية. حذف %1$s مسح %1$s مسح %1$s من الذاكرة المؤقتة @@ -2946,7 +2984,7 @@ هل ترغب حقًا في حذف المحادثة مع **%1$s**؟ هل أنت متأكد أنك تريد حذف المحادثة مع **%1$s** وحظره؟ هل ترغب حقًا في حذف **الرسائل المحفوظة**؟ - هل ترغب حقًا في حذف المحادثة السرية مع **%1$s**؟ + هل أنت متأكد أنك تريد حذف محادثك السرية مع **%1$s**؟ هل ترغب حقًا في حذف المحادثة **%1$s**؟ حذف المسودات السحابية هل ترغب حقًا في حذف جميع المسودات السحابية؟ @@ -3020,15 +3058,18 @@ لكي تتمكن من التواصل مع أصدقائك عبر جميع أجهزتك، ستتم مزامنة جهات اتصالك باستمرار مع خوادم تيليجرام السحابية شديدة التشفير. يحتاج تيليجرام للوصول لذاكرة التخزين لتتمكن من إرسال وحفظ الصور، المقاطع المرئية، الصوتيات وغيرها من الوسائط. - يحتاج تيليجرام إلى استخدام الميكروفون من أجل إرسال الرسائل الصوتية. + يحتاج تيليجرام الوصول للمايكروفون لتتمكن من إرسال الرسائل الصوتية. يحتاج تيليجرام إلى استخدام الميكروفون من أجل تسجيل المقاطع المرئية. يحتاج تيليجرام للوصول للكاميرا لتتمكن من أخذ الصور والمقاطع المرئية. يرجى تفعيلها في الإعدادات. يحتاج تيليجرام إلى السماح له بتحديد موقعك لتتمكن من مشاركته مع أصدقائك. يحتاج تيليجرام إلى صلاحية تحديد موقعك. يحتاج تيليجرام إلى صلاحية الظهور فوق التطبيقات لتشغيل المقاطع المرئية في وضع (صورة في الصورة). + "يتيح لك الوضع العائم استخدام المايكروفون ومعرفة من الذي يتحدث عندما تكون خارج تيليجرام. " الإعدادات يرجى السماح لتيليجرام بالظهور على شاشة القفل للتمكن من إجراء المكالمات دون مشاكل. - To share your live location in this chat, Telegram needs access to your location all the time, including while the app is in the background.\n\nWe will access your location only for the duration you choose, and you can stop sharing it any time. We won\'t use your location for any purpose other than sharing it in this chat. + "لمشاركة موقعك المباشر في هذه المحادثة؛ يحتاج تيليجرام الوصول إلى موقعك باستمرار، بما في ذلك أثناء عمل التطبيق في الخلفية.\n\n سنستخدم موقعك للمدة التي تختارها أنت فقط ويمكنك التوقف عن مشاركته في أي وقت. لن نستخدم موقعك لأي غرض بخلاف مشاركته في هذه المحادثة. " + صورة داخل صورة + المحادثة الصوتية العائمة النّمو المتابِعون @@ -3100,13 +3141,13 @@ أنشط المضيفين %s للرسالة الأيام النشطة - يقرؤون الرسائل + عرض الرسائل عرض الملف الشخصي اليوم يوم أمس المشاهدات - Public Shares - Private Shares + التحويل في العام + التحويلات في الخاص عرض الإحصائيات عرض إحصائيات القناة إحصائيات المنشور @@ -3141,9 +3182,14 @@ مكالمة تيليجرام مكالمة تيليجرام مرئية مكالمة تيليجرام الحالية + محادثة صوتية نشطة إنهاء المكالمة مكالمة أخرى نشطة - لديك حاليًا مكالمة نشطة مع **%1$s**. هل ترغب في إنهائها وبدءِ مكالمة جديدة مع **%2$s**؟ + إنهاء المكالمة مع **%1$s** وبدء واحدة جديدة مع **%2$s**؟ + "إنهاء المكالمة مع **%1$s** وبدء محادثة صوتية في **%2$s**؟ " + محادثة صوتية أخرى نشطة + مغادرة المحادثة الصوتية في **%1$s** وبدء أخرى في **%2$s**؟ + مغادرة المحادثة الصوتية في **%1$s** والاتصال بـ **%2$s**؟ المكالمات الصوتية "نغمة الرنين " يمكنك تخصيص نغمة الرنين عندما يتصل بك هذا المستخدم في تيليجرام. @@ -3160,7 +3206,9 @@ إجابة رفض أنت غير متصل حاليًا، قم بالاتصال بالإنترنت لتتمكن من إجراء المكالمات. + "أنت غير متصل حاليًا.يرجى الاتصال بالإنترنت للانضمام إلى المحادثات الصوتية. " لقد قمت بتفعيل وضع الطيران. يرجى تعطيله أو الاتصال بشبكة Wi-Fi لتتمكن من إجراء المكالمات. + "وضع الطيران يعمل لديك حاليًا. يرجى إيقاف تشغيله أو تشغيل الـ Wi-Fi للانضمام إلى المحادثات الصوتية. " غير متصل وضع الطيران الإعدادات @@ -3175,7 +3223,7 @@ مكالمة مرئية ملغاة مكالمة مرئية مرفوضة %1$s (%2$s) - لم تقم بإجراء أي مكالمة بعد. + ما من مكالمات هنا بعد... يستخدم تطبيق تيليجرام الخاص بـ**%1$s** بروتوكولًا غيرَ متوافقٍ، ينبغي عليهم تحديث تطبيقهم لتتمكن من الاتصال بهم. نسخة **%1$s** لا تدعم المكالمات؛ يَلزمُه تحديث تطبيقه قبل أن تتمكن من الاتصال به. عذرًا، يستخدم **%1$s** إصدارًا قديمًا من تيليجرام لا يدعم المكالمات المرئية. @@ -3191,7 +3239,7 @@ مكالمة تيليجرام مكالمة تيليجرام مرئية سماعة الأذن - سماعة الأذن + سماعة الرأس مكبر الصوت بلوتوث أجهزة الإخراج @@ -3226,9 +3274,14 @@ جودة الصورة رديئة اضغط هنا لتشغيل الكاميرا إلغاء الكتم + أو اضغط باستمرار للتحدث + أنت على الهواء + تم منعك من التحدّث + تم كتمه + أنت في وضع الاستماع فقط كتم تشغيل الكاميرا - إيقاف الكاميرا + الكاميرا مكبر الصوت تبديل الانتقال إلى مكالمة مرئية؟ @@ -3244,6 +3297,61 @@ هل أنت متأكد من إجراء مكالمة مرئية مع **%1$s**؟ مكالمة مرئية تتم معاودة الاتصال + بدء محادثة صوتية + محادثة صوتية + "بدء محادثة صوتية في هذه المجموعة؟ " + إدارة المحادثات الصوتيّة + انضمام + %1$s أعضاء يتحدثون + عضو واحد يتحدث + عضوان يتحدثان + %1$s أعضاء يتحدثون + %1$s عضوًا يتحدث + %1$s عضو يتحدث + يتحدث + يستمع + تمت دعوته + مغادرة + إنهاء + كتم المايكروفون + هل أنت متأكد أنك تريد كتم **%1$s** في هذه المحادثة الصوتية؟ + إزالة عضو + هل تريد إزالة %1$s من المجموعة؟ + تمت إزالة **%1$s** من المجموعة. + **%1$s** يمكنه الآن التحدّث. + تم كتم **%1$s** في هذه المحادثة. + كتم + السماح للمشاركين الجدد بالتحدث + كتم المشاركين الجدد + مشاركة رابط الدعوة + إنهاء المحادثة الصوتية + يتم الاتصال... + "مغادرة المحادثة الصوتية " + هل أنت متأكد أنك تريد مغادرة المحادثة الصوتية هذه؟ + إنهاء المحادثة الصوتية + "هل أنت متأكد أنك تريد إنهاء هذه المحادثة الصوتية؟ " + إنهاء المحادثة الصوتيّة + عرض المحادثة الصوتية + "محادثة صوتية " + فتح المحادثة الصوتية + "المستخدم المحدد موجود في هذه المحادثة الصوتية. " + عذرًا، لايمكنك الانضمام إلى المحادثات الصوتية كمشرف مجهول. + قام un1 بدعوة un2 إلى المحادثة الصوتية + الانضمام للمحادثة الصوتية + مرحبا! انضم إلى محادثتنا الصوتية: %1$s + دعوة الأعضاء + إزالة + السماح بالتحدّث + البحث عن أعضاء لدعوتهم... + نسخ رابط الدعوة + تم نسخ رابط الدعوة إلى الحافظة + إلغاء الكتم + "انتهت المحادثة الصوتية. بدء واحدة جديدة؟ " + إضافة عضو + "هل تريد إضافة **%1$s** إلى **%2$s**؟ " + أنت دعوت **%1$s** إلى المحادثة الصوتية. + إضافة + اضغط للانضمام مراسلة %1$s مكالمة صوتية %1$s @@ -3327,6 +3435,12 @@ %1$d أعضاء %1$d عضوًا %1$d عضو + %1$d مشاركين + %1$d مشارك + مشاركان + %1$d مشاركين + %1$d مشاركا + %1$d مشارك و%1$d عضو يكتب الآن وعضوٌ آخرُ يكتبان الآن وعضوان آخَران يكتبون الآن @@ -3345,12 +3459,12 @@ %1$d رسائل جديدة %1$d رسالة جديدة %1$d رسالة جديدة - %1$d messages unpinned - message unpinned - %1$d messages unpinned - %1$d messages unpinned - %1$d messages unpinned - %1$d messages unpinned + تم إلغاء تثبيت %1$d رسائل + تم إلغاء تثبيت رسالة + تم إلغاء تثبيت رسالتين + تم إلغاء تثبيت %1$d رسائل + تم إلغاء تثبيت %1$d رسالة + تم إلغاء تثبيت %1$d رسالة %1$d رسالة رسالة واحدة رسالتين @@ -3507,12 +3621,12 @@ %1$s مشاركات %1$s مشاركة %1$s مشاركة - %1$s public shares - %1$s public share - %1$s public shares - %1$s public shares - %1$s public shares - %1$s public shares + التحويلات في العام %1$s + التحويلات في العام %1$s + التحويلات في العام %1$s + التحويلات في العام %1$s + التحويلات في العام %1$s + التحويلات في العام %1$s %1$s مشاركة مشاركة واحدة مشاركتان @@ -3736,12 +3850,12 @@ تعليقات تعليقًا تعليق - %1$d Pinned Messages - Pinned Message - %1$d Pinned Messages - %1$d Pinned Messages - %1$d Pinned Messages - %1$d Pinned Messages + %1$d رسالة مثبّتة + رسالة واحدة مثبّتة + رسالتان مثبّتة + %1$d رسائل مثبّتة + %1$d رسالة مثبّتة + %1$d رسالة مثبّتة مجموعة قناة @@ -3751,6 +3865,9 @@ مجدولة لـ %s العودة للخلف فتح قائمة التنقل + فتح القائمة + إغلاق القائمة + Open in photo viewer %2$s من قِبل %1$s مزيد من الخيارات تشغيل @@ -3898,4 +4015,5 @@ \'ذكّرني اليوم عند\' HH:mm \'ذكّرني بتاريخ\' d MMM \'عند\' HH:mm \'ذكّرني بتاريخ\' d MMM yyyy \'عند\' HH:mm + تفعيل diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index c6eb7c3ea1e..ee28fbf73b4 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -127,7 +127,7 @@ Tippe unten auf den Stift für deine erste Chatnachricht. Tippe unten rechts auf den Stift\nfür deine erste Chatnachricht. Warte auf Netzwerk... - Verbinde... + Verbinden... Verbunden Ping: %1$d ms Prüfe... @@ -165,6 +165,7 @@ Anheften Loslösen Archivieren + Archiv Einblenden Archivierte Chats Chat löschen @@ -181,7 +182,7 @@ Stumm für %1$s Stumm aus In %1$s - Dauerhaft Stumm + Deaktivieren HASHTAGS Letzte Leute @@ -295,7 +296,7 @@ Nutzer, die von Admins aus dem Kanal entfernt wurden, können ihn nicht mehr über Einladungslinks betreten. Neuer Kanal Kanalname - Kontakte zum Kanal hinzufügen + Leute zum Kanal hinzufügen Mit einem dauerhaften Link können andere deinen Kanal finden und abonnieren. \n\nErlaubt sind a-z, 0-9 und Unterstriche.\nDie Mindestlänge beträgt 5 Zeichen. Mit einem dauerhaften Link können andere deine Gruppe finden und beitreten.\n\nErlaubt sind a-z, 0-9 und Unterstriche.\nDie Mindestlänge beträgt 5 Zeichen. Warnung @@ -371,9 +372,9 @@ Kanalvideo geändert Bild gelöscht Kanalname zu un2 geändert - Du hast leider zu viele öffentliche Benutzernamen erstellt. Du kannst jederzeit den Link einer älteren Gruppe oder eines Kanals entfernen. + Du hast leider zu viele öffentliche Benutzernamen erstellt. Du kannst jederzeit den Link einer älteren Gruppe oder eines Kanals entfernen oder private erstellen. Inhaber - Administrator + Admin Admin STUMM STUMM AUS @@ -384,7 +385,7 @@ Per Link einladen Admin entlassen Berechtigungen bearbeiten - Nur Administratoren sehen diese Liste. + Nur Kanal-Admins sehen diese Liste. Jeder, der Telegram installiert hat, kann anhand dieses Links in deinen Kanal. Administratoren helfen dir, deinen Kanal zu verwalten. Tippen und halten, um sie zu löschen. Möchtest du dem Kanal \'%1$s\' beitreten? @@ -444,7 +445,7 @@ Nachrichten von anderen löschen Nachrichten löschen Neue Admins hinzufügen - Anonym senden + Anonym bleiben Admin entlassen Neuen Inhaber ernennen Neuen Inhaber ernennen @@ -541,7 +542,7 @@ Wähle eine Gruppe aus, die Kommentare aus deinem Kanal anzeigen soll. Alles, was du in diesem Kanal veröffentlichst, wird an die Gruppe weitergeleitet. **%1$s** wurde als Gruppe für die Kanal-Kommentare ausgewählt. - **%1$s** verknüpft die Gruppe als Diskussionsgruppe. + Diese Gruppe dient %1$s\nals Diskussionsgruppe. Alle neuen Nachrichten, die in diesem Kanal veröffentlicht werden, werden an die Gruppe weitergeleitet. Neue Gruppe erstellen Gruppe nicht mehr verknüpfen @@ -567,6 +568,7 @@ Langsamer Modus ist aktiv, du kannst nicht mehr Elemente auswählen. Dieser Text ist für eine einzelne Nachricht leider zu lang.\n\nLangsamer Modus ist aktiv, du kannst nicht mehr als eine gleichzeitig senden. **%1$s** als Admin ernannt + **%1$s** aus **%2$s** entfernt Neue Umfrage Neues Quiz @@ -639,14 +641,14 @@ Letzte Aktionen Alle Aktionen - Ausgewählte Aktionen + ausgewählte Aktionen Alle Admins **Noch keine Aktionen!**\n\nMitglieder und Admins\nhaben noch keine Aktionen in den\nletzten 48 Stunden durchgeführt. **Noch keine Aktionen!**\n\nMitglieder und Admins\nhaben noch keine Aktionen\nin den letzten 48 Stunden durchgeführt. **Keine Aktionen gefunden**\n\nKeine kürzlichen Ereignisse gefunden,\ndie deinen Suchbegriff beinhalten. Keine kürzlichen Aktionen gefunden, die \'**%1$s**\' beinhalten. Was sind letzte Aktionen? - Das ist eine Liste aller Aktionen, die von Gruppenmitgliedern und Admins in den letzten 48 Stunden durchgeführt wurden. + Das ist eine Liste wichtiger Aktionen, die von Gruppenmitgliedern und Admins in den letzten 48 Stunden durchgeführt wurden. Das ist eine Liste aller Aktionen, die von Kanalmitgliedern und Admins in den letzten 48 Stunden durchgeführt wurden. un1 hat die Gruppe \"%1$s\" umbenannt un1 hat den Kanal in \"%1$s\" umbenannt @@ -675,8 +677,8 @@ un1 hat Umfrage beendet: un1 hat das Quiz beendet: un1 hat diese Nachricht gelöscht: - un1 hat Gruppenstandort zu \"%1$s\" geändert - un1 hat Gruppenstandort entfernt + un1 hat den Gruppenstandort zu \"%1$s\" geändert + un1 hat den Gruppenstandort entfernt hat Inhaberschaft an %1$s übertragen un1 hat das Sticker-Paket der Gruppe geändert un1 hat das Sticker-Paket der Gruppe entfernt @@ -716,8 +718,9 @@ Nachrichten bearbeiten Nachrichten löschen Admins hinzufügen - Anonym senden + Anonym bleiben Nutzer sperren + Sprachchats verwalten Nutzer hinzufügen Bezeichnung: %1$s Bezeichnung @@ -732,8 +735,15 @@ Bearbeitete Nachrichten Angeheftete Nachrichten Ehemalige Mitglieder + Sprachchats un1 hat den Timer des langsamen Modus auf %1$s gestellt un1 hat den langsamen Modus deaktiviert + un1 hat einen Sprachchat gestartet + un1 hat den Sprachchat beendet + un1 hat un2 in einem Sprachchat stummgeschaltet + un1 hat Stummschaltung von un2 in einem Sprachchat aufgehoben + un1 hat neuen Teilnehmern im Sprachchat erlaubt zu sprechen + un1 hat neue Teilnehmer des Sprachchats stummgeschaltet Neue Broadcast Liste Listenname @@ -810,8 +820,8 @@ %1$s spielt ein Spiel... %1$s sendet Video... %1$s sendet Datei... - nimmt eine Sprachnachricht auf... - nimmt eine Videonachricht auf... + nimmt Sprachnachricht auf... + nimmt Videonachricht auf... schickt Audio... schickt Bild... spielt ein Spiel... @@ -852,7 +862,7 @@ WISCHEN UM ABZUBRECHEN In Downloads speichern GIF hinzufügen - GIF löschen? + GIF aus diesem Bereich löschen? Musik speichern Teilen Sprachdatei benutzen @@ -904,7 +914,7 @@ Nachricht anheften Nachricht loslösen Möchtest du eine ältere Nachricht anheften, während du eine neuere Nachricht angeheftet lässt? - Wirklich diese Nachricht in der Gruppe für alle Mitglieder anheften? + Diese Nachricht in der Gruppe anheften? Nachricht im Kanal wirklich anheften? Möchtest du diese Nachricht ganz oben im Chat anheften? Angeheftete Nachricht wieder entfernen? @@ -935,6 +945,13 @@ Nachricht bearbeiten Beschriftung bearbeiten Antippen, um Medium zu bearbeiten + Bild bearbeiten + Dieses Video bearbeiten + Bild ersetzen + Video ersetzen + Medium ersetzen + Datei ersetzen + Audiodatei ersetzen Runterscrollen für Bots %1$s Bearbeitungszeit leider abgelaufen. @@ -1003,6 +1020,8 @@ Tippen für Foto, halten für Video Antippen für Listenansicht Ohne Ton senden + Als neues Bild senden + Bild ersetzen Jetzt senden Umplanen Heute @@ -1052,7 +1071,7 @@ Bot-Inhaberschaft übertragen Das wird die **vollständigen Eigentümerrechte** des Bots an den ausgewählten Nutzer übertragen. Inhaber ändern - Nur so kannst du einen Bot übertragen: + So kannst du nur diesen Bot übertragen: Kommentar hinterlassen Kommentare Kommentar @@ -1116,7 +1135,7 @@ %1$s hat eine Datei an die Gruppe %2$s gesendet %1$s hat ein GIF an die Gruppe %2$s gesendet %1$s hat eine Rechnung der Gruppe %2$s für %3$s gesendet - %1$s hat eine Sprachnachricht an die Gruppe %2$s gesendet + %1$s hat eine Sprachnachricht an %2$s gesendet %1$s hat eine Videonachricht an die Gruppe %2$s gesendet %1$s hat Audiodatei an die Gruppe %2$s gesendet %1$s hat einen Sticker an die Gruppe %2$s gesendet @@ -1126,13 +1145,17 @@ %1$s hat das Gruppenbild von %2$s geändert %1$s hat das Gruppenvideo bei %2$s geändert %1$s hat %3$s in die Gruppe %2$s eingeladen + %1$s hat %3$s in den Sprachchat in %2$s eingeladen + %1$s hat dich in den Sprachchat in %2$s eingeladen + %1$s hat einen Sprachchat in %2$s gestartet + %1$s hat Sprachchat in der Gruppe %2$s beendet %1$s ist in die Gruppe %2$s zurückgekehrt %1$s ist der Gruppe %2$s beigetreten %1$s hat %3$s aus der Gruppe %2$s entfernt %1$s hat dich aus der Gruppe %2$s entfernt %1$s hat die Gruppe %2$s verlassen %1$s benutzt jetzt Telegram! - %1$s,\nWir haben eine Anmeldung von einem neuen Gerät am %2$s festgestellt.\n\nGerät: %3$s\nStandort: %4$s\n\nWenn du das nicht selbst gewesen bist, melde die entsprechende Sitzung in den Telegram Einstellungen unter Privatsphäre und Sicherheit - Sitzungen unverzüglich ab.\n\nKennst du schon unsere zweistufige Bestätigung? Diese kannst du in den Telegram Einstellungen unter Privatsphäre und Sicherheit optional aktivieren.\n\nDein Telegram Team + %1$s,\nwir haben eine Anmeldung von einem neuen Gerät am %2$s festgestellt.\n\nGerät: %3$s\nStandort: %4$s\n\nWenn du das nicht selbst gewesen bist, melde die entsprechende Sitzung in den Telegram Einstellungen unter Geräte unverzüglich ab.\n\nWenn du der Meinung bist, dass sich jemand gegen deinen Willen bei deinem Konto angemeldet hat, kannst du in den Einstellungen unter Privatsphäre und Sicherheit die zweistufige Bestätigung aktivieren.\n\nDein Telegram Team %1$s hat das Profilbild geändert %1$s ist per Einladungslink der Gruppe %2$s beigetreten %1$s hat %3$s an die Gruppe %2$s gesendet @@ -1158,7 +1181,7 @@ %1$s hat eine Datei in der Gruppe %2$s angeheftet %1$s hat einen Sticker in der Gruppe %2$s angeheftet %1$s hat einen %3$s Sticker in der Gruppe %2$s angeheftet - %1$s hat eine Sprachnachricht in der Gruppe %2$s angeheftet + %1$s hat eine Sprachnachricht bei %2$s angeheftet %1$s hat eine Videonachricht in der Gruppe %2$s angeheftet %1$s hat einen Kontakt %3$s in der Gruppe %2$s angeheftet %1$s hat einen Standort in der Gruppe %2$s angeheftet @@ -1262,6 +1285,7 @@ BEITRETEN Link in die Zwischenablage kopiert Link in Zwischenablage kopiert.\nDer Link funktioniert nur für Mitglieder dieses Chats. + This link will only work for members of this chat. Leider kannst du auf diese Nachricht nicht zugreifen. Du bist kein Mitglied des Chats, in dem sie veröffentlicht wurde. Telefon in die Zwischenablage kopiert E-Mail in die Zwischenablage kopiert @@ -1284,7 +1308,7 @@ Einstellungen Abonnent hinzufügen Mitglied hinzufügen - Administratoren + Admins festlegen NUTZER EINSCHRÄNKEN Löschen und Gruppe verlassen Löschen und Gruppe verlassen @@ -1366,7 +1390,7 @@ Benutzername leider nicht erlaubt. Ein Benutzername benötigt mindestens 5 Zeichen. Ein Benutzername darf maximal 32 Zeichen haben. - Benutzernamen dürfen leider nicht mit einer Zahl anfangen. + Darf nicht mit einer Zahl beginnen. Wähle einen öffentlichen Benutzernamen, wenn du von anderen bei **Telegram** gefunden werden willst — ohne, dass sie deine Nummer kennen müssen.\n\nErlaubt sind **a–z**, **0–9** und Unterstriche. Die Mindestlänge beträgt **5** Zeichen. Dieser Link öffnet einen Chat mit dir:\n%1$s Prüfe Benutzername... @@ -1435,7 +1459,7 @@ Archivierte Masken Keine archivierten Sticker Keine archivierten Masken - Bis zu 200 Sticker-Pakete kannst du installieren.\nAlle folgenden werden archiviert. + Bis zu 200 Sticker-Pakete kannst du installieren.\nVorherige werden danach archiviert. Bis zu 200 Masken-Pakete kannst du installieren. Unbenutzte werden archiviert, sobald du neue installierst. STICKER SENDEN Archivierte Sticker @@ -1814,6 +1838,10 @@ In-Chat-Töne Standard Standard + Standard + In-App Standard + %1$s In-App + Lautlos Schlaue Benachrichtigungen Ausnahmen Eine Ausnahme hinzufügen @@ -1960,7 +1988,7 @@ Berechne... Dateien Bilder - Sprach-/Videonachrichten + Sprach- & Videonachrichten Videos Musik GIFs @@ -2160,7 +2188,7 @@ Vietnamesisch Aktive Sitzungen - Aktuelle Sitzung + Dieses Gerät Keine anderen Sitzungen Du kannst dich von jedem Handy, Tablet und Computer bei Telegram mit derselben Telefonnummer anmelden. Alles wird immer sofort synchronisiert. Aktive Sitzungen @@ -2574,6 +2602,7 @@ Zurück zu Einstellungen Zurück zu Passport Passwort festlegen + Show password Zusätzliches Passwort festlegen Hier kannst du ein eigenes Passwort festlegen, um dich an einem neuen Gerät anzumelden, zusätzlich zum Code, der per SMS kommt. Dein Passwort @@ -2630,7 +2659,7 @@ Wiederherstellungscode Wir haben den Wiederherstellungscode an diese Adresse geschickt:\n\n%1$s Überprüfe deine Mails und gib den 6-stelligen Code aus unserer E-Mail ein. - Du hast keinen Zugang zu deiner Adresse %1$s? + Keinen Zugang zu %1$s? Kein Zugang zu deiner E-Mail-Adresse? Wenn du nicht in deine E-Mails kommst, kannst du nur hoffen, dass dir dein Passwort wieder einfällt oder du musst dein Telegram-Konto zurücksetzen. KONTO ZURÜCKSETZEN @@ -2654,6 +2683,7 @@ Daten- und Speichernutzung Speichernutzung Datenbenutzung + Speicherpfad Mobil WLAN Roaming @@ -2676,7 +2706,7 @@ Privatsphäre und Sicherheit Privatsphäre Zuletzt gesehen - Profilbild + Profilbilder Wer darf mein Profilbild sehen? Hier kannst du per Feineinstellung bestimmen, wer dein Profilbild sehen darf. Du kannst Kontakte oder ganze Gruppen hinzufügen, für die eine Ausnahme gemacht werden soll. @@ -2852,6 +2882,14 @@ un1 ist jetzt %1$s von dir entfernt Du befindest dich jetzt innerhalb %1$s von un1 un1 ist jetzt %1$s von un2 entfernt + un1 hat dich in diese Gruppe eingeladen + un1 hat dich in diesen Kanal eingeladen + un1 hat einen Sprachchat gestartet + Du hast einen Sprachchat gestartet + Sprachchat beendet (%s) + un1 hat un2 in den Sprachchat eingeladen + Du hast un2 in den Sprachchat eingeladen + un1 hat dich in den Sprachchat eingeladen Du hast diesem Bot erlaubt, dich anzuschreiben, als du dich auf %1$s angemeldet hast. %1$s hat die folgenden Dokumente erhalten: %2$s Persönliche Daten @@ -2867,7 +2905,7 @@ Mietvertrag Telefonnummer E-Mail-Adresse - Diese Nachricht wird von deiner Telegram-Version nicht unterstützt. Bitte aktualisiere Telegram um sie zu sehen: https://telegram.org/update + Diese Nachricht wird von deiner Telegram-Version nicht unterstützt. Bitte aktualisiere die App: https://telegram.org/update Bild Video Selbstzerstörendes Bild @@ -2910,7 +2948,7 @@ Code ist abgelaufen, bitte melde dich erneut an Zu viele Versuche in zu kurzer Zeit, versuche es bitte später erneut. Zu viele Versuche, bitte erneut in %1$s versuchen - Ungültiger Code + Ungültiger Code. Bitte versuche es später erneut. Du hast dein Konto leider zu oft gelöscht. Bitte warte einige Tage, erst dann kannst du dich erneut registrieren. Ungültiger Vorname Dieser Name kann leider nicht benutzt werden @@ -2946,7 +2984,7 @@ Wirklich den Chat mit **%1$s** löschen? Wirklich **%1$s** blockieren und den Chat löschen? Wirklich den Chat **Gespeichertes** löschen? - Wirklich den Geheimen Chat mit **%1$s** löschen? + Wirklich deinen Geheimen Chat mit **%1$s** löschen? Wirklich den Chat **%1$s** löschen? Cloud-Entwürfe löschen Wirklich all deine Cloud-Entwürfe löschen? @@ -3026,9 +3064,12 @@ "Telegram benötigt Zugriff auf deinen Standort, damit du ihn mit Freunden teilen kannst. " Telegram benötigt Zugriff auf deinen Standort. Telegram braucht Zugriff auf die Funktion \'Über andere Apps einblenden\'. Nur so können Videos im Bild in Bild Modus wiedergegeben werden. + Der Überlagerungsmodus erlaubt dir die Verwendung von Push-To-Talk und die Anzeige, wer gerade spricht, selbst wenn du dich ausserhalb von Telegram befindest. EINSTELLUNGEN Bitte erlaube Telegram auf dem Sperrbildschirm, damit Anrufe signalisiert werden können. Um deinen Live-Standort in diesem Chat zu teilen, muss Telegram die ganze Zeit Zugang zu deinem Standort haben, auch während die App im Hintergrund läuft.\n\nWir greifen nur für die von dir gewählte Dauer auf deinen Standort zu und du kannst jederzeit aufhören, ihn zu teilen. Wir werden deinen Standort für keinen anderen Zweck nutzen, als ihn in diesem Chat zu teilen. + Bild-in-Bild + Sprachchat-Überlagerung Wachstum Abonnenten @@ -3129,7 +3170,7 @@ Kontoeinstellungen Weniger Daten benutzen Eingehender Anruf - Verbinde + Verbinden Tausche Schlüssel aus Warte Wird angefordert @@ -3141,9 +3182,14 @@ Telegram-Anruf Telegram Videoanruf Laufender Telegram-Anruf + Laufender Sprachchat Auflegen Ein anderer Anruf ist bereits aktiv - Du bist mit **%1$s** bereits im Gespräch. Möchtest du den Anruf beenden und einen neuen mit **%2$s** starten? + Gespräch mit **%1$s** beenden und neues mit **%2$s** beginnen? + Gespräch mit **%1$s** beenden und neuen Sprachchat bei **%2$s** starten? + Es ist bereits ein anderer Sprachchat aktiv + Sprachchat bei **%1$s** verlassen und einen neuen bei **%2$s** starten? + Sprachchat in **%1$s** verlassen und **%2$s** anrufen? Anrufe Klingelton Hier kannst du den Klingelton für Sprachanrufe festlegen. @@ -3160,7 +3206,9 @@ Annehmen Ablehnen Du bist derzeit offline. Bitte verbinde dich mit dem Internet und versuche es erneut. + Du bist offline. Bitte verbinde dich mit dem Internet, um an Sprachchat teilzunehmen. Du hast derzeit den Flugmodus aktiviert. Deaktiviere den Flugmodus oder verbinde dich per W-LAN um jemanden anzurufen. + Derzeit nutzt du den Flugmodus, deaktiviere diesen oder verbinde dich mit einem W-LAN, um Sprachchats teilzunehmen. Offline Flugmodus Einstellungen @@ -3226,10 +3274,15 @@ Video war verpixelt Hier tippen, um Kamera einzuschalten Stumm aus + oder halten und sprechen + Du bist live + Durch Admin stummgeschaltet + Stumm + Du befindest dich im Nur-Zuhören-Modus Stumm Video ein Video aus - Lautsprecher + Audio Wechseln Zu Videoanruf wechseln? WECHSELN @@ -3244,6 +3297,61 @@ Wirklich einen Videoanruf mit **%1$s** starten? Videoanruf Erneut verbinden + Sprachchat erstellen + Sprachchat + Sprachchat in dieser Gruppe starten? + Sprachchats verwalten + Beitreten + %1$s Mitglieder sprechen + %1$s Mitglied spricht + %1$s Mitglieder sprechen + %1$s Mitglieder sprechen + %1$s Mitglieder sprechen + %1$s Mitglieder sprechen + spricht + hört zu + eingeladen + Verlassen + Beenden + Mikrofon stummschalten + Wirklich **%1$s** in diesem Sprachchat stummschalten? + Mitglied entfernen + %1$s wirklich aus der Gruppe entfernen? + **%1$s** aus der Gruppe entfernt. + **%1$s** kann jetzt sprechen. + **%1$s** ist jetzt stummgeschaltet. + Stumm ein + Neue dürfen sprechen + Neue sind stumm + Einladungslink teilen + Sprachchat beenden + Verbinden... + Sprachchat verlassen + Wirklich diesen Sprachchat verlassen? + Sprachchat beenden + Wirklich diesen Sprachchat beenden? + Sprachchat beenden + SPRACHCHAT + Sprachchat + Sprachchat öffnen + Ausgewählter Nutzer ist bereits in diesem Sprachchat. + Leider kannst du an Sprachchats als anonymer Admin nicht teilnehmen. + un1 hat un2 in den Sprachchat eingeladen + Am Sprachchat teilnehmen + Hallo! Tritt unserem Sprachchat bei: %1$s + Mitglieder einladen + Entfernen + Darf sprechen + Mitglieder zum Anruf hinzufügen + Einladungslink kopieren + Einladungslink in Zwischenablage kopiert. + Stumm aus + Sprachchat beendet. Neuen starten? + Mitglied hinzufügen + **%1$s** zu **%2$s** hinzufügen? + Du hast **%1$s** in den Sprachchat eingeladen. + Hinzufügen + Zum Beitreten antippen Nachricht in Telegram %1$s Sprachanruf in Telegram %1$s @@ -3327,6 +3435,12 @@ %1$d Mitglieder %1$d Mitglieder %1$d Mitglieder + %1$d Teilnehmer + %1$d Teilnehmer + %1$d Teilnehmer + %1$d Teilnehmer + %1$d Teilnehmer + %1$d Teilnehmer und %1$d weitere tippen und %1$d weitere tippen und %1$d weitere tippen @@ -3751,6 +3865,9 @@ Geplant am %s Zurückgehen Navigationsmenü öffnen + Menü öffnen + Menü schliessen + Open in photo viewer %2$s von %1$s Weitere Optionen Abspielen @@ -3898,4 +4015,5 @@ \'Heute um\' HH:mm \'erinnern\' \'Am\' d MMM \'um\' HH:mm \'erinnern\' \'Am\' d MMM yyyy \'um\' HH:mm \'erinnern\' + Aktivieren diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 7c3ca4f5688..e495cb75d88 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -39,7 +39,7 @@ No restablecer la cuenta Alguien con acceso a **%1$s** solicitó eliminar tu cuenta de Telegram y restablecer tu contraseña de la verificación en dos pasos.\n\nSi no fuiste tú, por favor, escribe el código que enviamos por SMS. También puedes cancelar la solicitud *cambiando tu número de teléfono*. Restablecer la cuenta - Como la cuenta **%1$s** está activa y protegida con una contraseña, la eliminaremos en 1 semana, por motivos de seguridad.\n\nPuedes cancelar el proceso en cualquier momento. + Como la cuenta **%1$s** está activa y protegida con una contraseña, la eliminaremos en 1 semana. Esta espera es necesaria por razones de seguridad.\n\nPuedes cancelar este proceso en cualquier momento. Podrás restablecer tu cuenta en: Tus intentos recientes de restablecer esta cuenta fueron cancelados por su usuario activo. Por favor, reinténtalo en 7 días. RESTABLECER CUENTA @@ -53,8 +53,8 @@ Apellidos (opcional) Cancelar registro - Has transferido satisfactoriamente %1$s a %2$s por %3$s - Has transferido satisfactoriamente %1$s a %2$s + Transferiste satisfactoriamente %1$s a %2$s por %3$s + Transferiste satisfactoriamente %1$s a %2$s Caja Forma de envío Lo sentimos, pero no es posible hacer envíos a tu dirección. @@ -165,6 +165,7 @@ Fijar Desfijar Archivar + Archivo Desarchivar Chats archivados Eliminar chat @@ -172,7 +173,7 @@ Elige un chat Reenviar a... Foto secreta - Video secreto + Video temporal GIF secreto %1$s usa una versión antigua de Telegram, así que las fotos secretas serán mostradas en un modo de compatibilidad.\n\nCuando %2$s actualice Telegram, las fotos con autodestrucción de 1 minuto o menos funcionarán con el modo “Mantén pulsado para ver”, y te notificaremos siempre que la otra parte haga una captura de pantalla. Mensajes @@ -181,7 +182,7 @@ Silenciar %1$s Notificar En %1$s - Silenciar para siempre + Desactivar HASHTAGS Recientes Personas @@ -253,7 +254,7 @@ Mensaje desfijado Promover a administrador - Permisos de administrador + Editar privilegios del admin. Sin usuarios eliminados Eliminar grupo Salir del grupo @@ -267,7 +268,7 @@ ¿Quieres salir de **%1$s**? Lo sentimos, no puedes añadir a este usuario a grupos. Lo sentimos, el grupo está lleno. - Lo sentimos, si una persona ya no forma parte de un grupo, deben añadirse como contactos para que pueda regresar.\n\nTen en cuenta que puede unirse usando el enlace de invitación del grupo si no está en la lista de usuarios eliminados. + Si una persona ya no forma parte de un grupo, necesitas estar dentro de sus contactos de Telegram para añadirla nuevamente.\n\nTen en cuenta que puede unirse usando el enlace de invitación del grupo si no está en la lista de usuarios eliminados. Hay demasiados administradores en el grupo. El usuario objetivo tiene demasiados grupos o canales públicos. Por favor, pídele que haga privado uno de sus grupos o canales existentes primero. El usuario objetivo tiene demasiados grupos por ubicación. Por favor, pídele eliminar o transferir uno de los existentes primero. @@ -295,7 +296,7 @@ Los usuarios que fueron eliminados del canal por los administradores no pueden volver a unirse con enlaces de invitación. Nuevo canal Nombre del canal - Añadir contactos a tu canal + Añadir personas a tu canal Si estableces un enlace permanente, otras personas podrán encontrar tu canal y unirse a él.\n\nPuedes usar a-z, 0-9 y guiones bajos.\nLa longitud mínima es de 5 caracteres. Si estableces un enlace permanente, otras personas podrán encontrar tu grupo y unirse a él.\n\nPuedes usar a-z, 0-9 y guiones bajos.\nLa longitud mínima es de 5 caracteres. Advertencia @@ -371,7 +372,7 @@ Video del canal cambiado Foto del canal eliminada Nombre del canal cambiado a un2 - Lo sentimos, tienes demasiados nombres de usuario públicos. Puedes anular el enlace de uno de tus grupos o canales anteriores, o crear uno privado. + Tienes demasiados enlaces públicos. Puedes anular el enlace de uno de tus grupos o canales anteriores, o crear uno privado. Propietario Administrador Administrador @@ -393,7 +394,7 @@ Lamentablemente, tienes prohibido participar en grupos públicos. Lo sentimos, este chat ya no es accesible. ¿Añadir a %1$s al canal? - Lo sentimos, si una persona ya no forma parte de un canal, deben añadirse como contactos para que pueda regresar.\n\nTen en cuenta que puede unirse usando el enlace de invitación del canal si no está en la lista de usuarios eliminados. + Si una persona ya no forma parte de un canal, necesitas estar dentro de sus contactos de Telegram para añadirla nuevamente.\n\nTen en cuenta que puede unirse usando el enlace de invitación del grupo si no está en la lista de usuarios eliminados. Lo sentimos, no puedes añadir a este usuario a canales. Hay demasiados administradores en el canal. Hay demasiados bots en este canal. @@ -433,12 +434,12 @@ Tu post no será notificado Firmar los mensajes Añade los nombres de los administradores a sus posts. - Permisos de administrador + Privilegios del admin. Título personalizado Un título personalizado se mostrará a todos los miembros en lugar de “%1$s”. ¿Qué puede hacer este administrador? - Cambiar info. del canal - Cambiar info. del grupo + Editar info. del canal + Editar info. del grupo Publicar mensajes Editar mensajes de otros Eliminar mensajes de otros @@ -464,11 +465,11 @@ Invitar con un enlace Fijar mensajes Promovido por %1$s - No puedes editar los permisos de este administrador. + No puedes editar los privilegios de este administrador. No puedes editar este permiso. Este permiso no está disponible en grupos públicos. Eliminado por %1$s - Permisos de usuario + Permisos del usuario Esta opción está desactivada para todos los miembros en Permisos de grupo ¿Qué puede hacer este usuario? Leer mensajes @@ -477,7 +478,7 @@ Enviar encuestas Enviar stickers y GIF Incrustar enlaces - Cambiar info. del chat + Editar info. del chat Fijar mensajes Añadir usuarios no puede leer @@ -522,7 +523,7 @@ Enlace Toca para añadir un enlace permanente Elegir foto - Elegir foto o video + Elige una foto o video Poner nueva foto Tomar foto Grabar video @@ -530,8 +531,8 @@ Elegir desde Galería Buscar en la web Estadísticas - Los bots pueden ser añadidos sólo como administradores. - Lo sentimos, los bots pueden ser añadidos a canales sólo como administradores. + Los bots sólo pueden ser añadidos como administradores. + Los bots sólo pueden ser añadidos a canales como administradores. PROMOVER A ADMINISTRADOR %1$s se eliminará de los administradores si le aplicas restricciones. Conversación @@ -541,7 +542,7 @@ Elige el grupo que alojará los comentarios de tu canal. Todo lo que publiques en el canal será reenviado a este grupo. **%1$s** está seleccionado como el grupo que aloja los comentarios de tu canal. - Este grupo está vinculado como grupo de conversación de **%1$s**. + Este chat está vinculado como grupo de conversación de **%1$s**. Todo lo que publiques en este canal será reenviado a este grupo. Crear un nuevo grupo Desvincular grupo @@ -567,6 +568,7 @@ El modo lento está activo. No puedes seleccionar más ítems. Lo sentimos, este texto es muy largo para ser enviado en un mensaje.\n\nEl modo lento está activo. No puedes enviar más de un mensaje a la vez. **%1$s** promovido a administrador + **%1$s** fue eliminado de **%2$s** Nueva encuesta Nuevo cuestionario @@ -639,14 +641,14 @@ Acciones recientes Todas las acciones - Acciones elegidas + acciones elegidas Todos los administradores **Aún no hay eventos**\n\nLos administradores del grupo\nno han realizado acciones de servicio\nen las últimas 48 horas. **Aún no hay eventos**\n\nLos administradores del canal\nno han realizado acciones de servicio\nen las últimas 48 horas. **No se encontraron acciones**\n\nNo se encontraron acciones recientes\nque coincidan con tu consulta. No se encontraron acciones recientes que contengan “**%1$s**”. ¿Qué son las acciones recientes? - Esta es una lista de las acciones de servicio realizadas por los miembros y administradores del grupo en las últimas 48 horas. + Esta es una lista de acciones importantes realizadas por los miembros y administradores en las últimas 48 horas. Esta es una lista de las acciones de servicio realizadas por los administradores del canal en las últimas 48 horas. un1 renombró el grupo a “%1$s” un1 renombró el canal a “%1$s” @@ -702,7 +704,7 @@ cambió los permisos por defecto Enviar stickers y GIF Enviar multimedia - Cambiar info. + Editar info. Añadir usuarios Fijar mensajes Enviar encuestas @@ -710,21 +712,22 @@ Incrustar enlaces Leer mensajes cambió los privilegios de %1$s - Cambiar info. del canal - Cambiar info. del grupo + Editar info. del canal + Editar info. del grupo Publicar mensajes Editar mensajes Eliminar mensajes Añadir administradores Ser anónimo Suspender usuarios + Gestionar chats de voz Añadir usuarios Título: %1$s Título Fijar mensajes Todas las acciones Nuevas excepciones - Permisos de administrador + Privilegios de administrador Nuevos miembros Info. del grupo Info. del canal @@ -732,8 +735,15 @@ Mensajes editados Mensajes fijados Miembros que salieron + Chats de voz un1 estableció el modo lento a %1$s un1 desactivó el modo lento + un1 inició el chat de voz + un1 finalizó el chat de voz + un1 silenció a un2 en el chat de voz + un1 dejó de silenciar a un2 en el chat de voz + un1 permitió hablar a los nuevos participantes del chat de voz + un1 silenció a los nuevos participantes del chat de voz Nueva difusión Nombre de la lista @@ -749,7 +759,7 @@ Música Artista desconocido Título desconocido - Repetir canción + Repetir pista Repetir lista Lista aleatoria Invertir orden @@ -847,12 +857,12 @@ Saliste de este grupo Eliminar este grupo Eliminar este chat - Eliminar este chat + Eliminar este chat para ambos Eliminar chats DESLIZA PARA CANCELAR Guardar en Descargas Guardar GIF - ¿Eliminar GIF? + ¿Quieres eliminar el GIF de esta sección? Guardar en música Compartir Aplicar traducción @@ -904,7 +914,7 @@ Fijar mensaje Desfijar mensaje ¿Quieres fijar un mensaje más antiguo y a la vez mantener fijado uno más reciente? - ¿Quieres fijar este mensaje para todos los miembros del grupo? + ¿Quieres fijar este mensaje en el grupo? ¿Quieres fijar este mensaje en el canal? ¿Quieres fijar este mensaje en la parte de arriba del chat? ¿Quieres desfijar este mensaje? @@ -935,6 +945,13 @@ Editar mensaje Editar comentario Toca para reemplazar + Editar esta foto + Editar este video + Reemplazar foto + Reemplazar video + Reemplazar multimedia + Reemplazar archivo + Reemplazar audio Ve abajo para los bots %1$s Lo sentimos, terminó el tiempo de edición. @@ -949,7 +966,7 @@ Hasta 200.000 miembros Historial de chat persistente Enlaces públicos como t.me/title - Administradores con diferentes permisos + Admins. con diferentes privilegios Guarda mensajes reenviándolos aquí Envía archivos para almacenarlos Accede desde cualquier dispositivo @@ -1003,6 +1020,8 @@ Toca para foto, mantén para video Toca para ver como lista. Enviar sin sonido + Enviar como una nueva foto + Reemplazar foto Enviar ahora Reprogramar Hoy @@ -1116,7 +1135,7 @@ %1$s envió un archivo al grupo %2$s %1$s envió un GIF al grupo %2$s %1$s envió una factura al grupo %2$s por %3$s - %1$s envió un mensaje de voz al grupo %2$s + %1$s envió un mensaje de voz a %2$s %1$s envió un videomensaje al grupo %2$s %1$s envió un audio al grupo %2$s %1$s envió un sticker al grupo %2$s @@ -1126,13 +1145,17 @@ %1$s cambió la foto del grupo %2$s %1$s cambió el video del grupo %2$s %1$s añadió a %3$s al grupo %2$s + %1$s añadió a %3$s al chat de voz en %2$s + %1$s te invitó al chat de voz en %2$s + %1$s inició el chat de voz en %2$s + %1$s finalizó el chat de voz en %2$s %1$s volvió al grupo %2$s %1$s se unió al grupo %2$s %1$s eliminó a %3$s del grupo %2$s %1$s te eliminó del grupo %2$s %1$s salió del grupo %2$s ¡%1$s se unió a Telegram! - %1$s,\nDetectamos un inicio de sesión en tu cuenta desde un nuevo dispositivo, el %2$s\n\nDispositivo: %3$s\nUbicación: %4$s\n\nSi no eras tú, puedes ir a Ajustes > Privacidad y seguridad > Sesiones activas y cerrar esa sesión.\n\nSi crees que alguien ha iniciado la sesión sin tu consentimiento, puedes activar la verificación en dos pasos, en los ajustes de privacidad y seguridad.\n\nAtentamente,\nEl equipo de Telegram + %1$s:\nDetectamos un inicio de sesión en tu cuenta desde un nuevo dispositivo el %2$s\n\nDispositivo: %3$s\nUbicación: %4$s\n\nSi no eras tú, puedes ir a Ajustes > Dispositivos y cerrar esa sesión.\n\nSi crees que alguien inició sesión en tu cuenta sin tu consentimiento, puedes activar la verificación en dos pasos en los ajustes de privacidad y seguridad.\n\nAtentamente,\nEl equipo de Telegram %1$s cambió su foto de perfil %1$s se unió al grupo %2$s con un enlace de invitación %1$s envió %3$s al grupo %2$s @@ -1158,7 +1181,7 @@ %1$s ancló un archivo en el grupo %2$s %1$s fijó un sticker en el grupo %2$s %1$s fijó un %3$s sticker en el grupo %2$s - %1$s fijó un mensaje de voz en el grupo %2$s + %1$s fijó un mensaje de voz en %2$s %1$s fijó un videomensaje en el grupo %2$s %1$s fijó un contacto %3$s en el grupo %2$s %1$s fijó un mapa en el grupo %2$s @@ -1245,7 +1268,7 @@ Encuentra personas cerca para chatear Busca personas por nombre de usuario Nuevo contacto - El número de teléfono **%1$s** no está en tu lista de contactos. ¿Quieres añadirlo? + El número de teléfono **%1$s** no está en tus contactos. ¿Quieres añadirlo? Añadir contacto Añadir personas... @@ -1262,6 +1285,7 @@ UNIRME Enlace copiado al portapapeles Enlace copiado al portapapeles.\nEste enlace sólo funcionará para miembros de este chat. + This link will only work for members of this chat. Lamentablemente, no puedes acceder a este mensaje. No eres miembro del chat en el que fue publicado. Teléfono copiado al portapapeles Correo copiado al portapapeles @@ -1284,19 +1308,19 @@ Ajustes Añadir suscriptores Añadir miembros - Administradores + Añadir admins. SUSPENDER DEL GRUPO Eliminar y salir del grupo Eliminar y salir del grupo Notificaciones - Permisos de usuario + Cambiar permisos Eliminar del grupo Convertir en supergrupo Convertir en supergrupo Convertir en supergrupo Advertencia Esta acción es irreversible. No puedes convertir un supergrupo en un grupo normal. - **Límite de miembros alcanzado.**\n\nPara superar el límite y tener características adicionales, conviértelo en un supergrupo:\n\n• Permiten hasta %1$s\n• Los nuevos miembros ven todo el historial\n• Un mensaje eliminado desaparece para todos\n• Puede añadirse una descripción para el grupo\n• El creador puede generar un enlace público + **Límite de miembros alcanzado.**\n\nPara tener más espacio y características adicionales, conviértelo en un supergrupo:\n\n• Permiten hasta %1$s\n• Los nuevos miembros ven todo el historial\n• Un mensaje eliminado desaparece para todos\n• Los admins. pueden añadir una descripción\n• El propietario puede generar un enlace público **En los supergrupos:**\n\n• Los nuevos miembros ven todo el historial\n• Un mensaje eliminado desaparece para todos\n• Puede añadirse una descripción para el grupo\n• El creador puede generar un enlace público **Importante:** Esta acción no se puede deshacer. @@ -1366,8 +1390,8 @@ Lo sentimos, este nombre de usuario no es válido. Un nombre de usuario debe tener al menos 5 caracteres. El nombre de usuario no debe exceder los 32 caracteres. - Lo sentimos, un nombre de usuario no puede comenzar con un número. - Puedes elegir un nombre de usuario en **Telegram**. Si lo haces, otras personas te podrán encontrar por ese nombre y contactarte sin saber tu número de teléfono.\n\nPuedes usar **a–z**, **0–9** y guiones bajos.\nLa longitud mínima es de **5** caracteres. + Los nombres de usuario no pueden comenzar con un número. + Puedes elegir un nombre de usuario en **Telegram**. Si lo haces, las personas te podrán encontrar por ese nombre y contactarte sin saber tu número de teléfono.\n\nPuedes usar **a–z**, **0–9** y guiones bajos.\nLa longitud mínima es de **5** caracteres. Este enlace abre un chat contigo:\n%1$s Verificando nombre de usuario... %1$s está disponible. @@ -1435,7 +1459,7 @@ Máscaras archivadas Stickers no archivados Sin máscaras archivadas - Puedes añadir hasta 200 packs de stickers.\nSi añades más, se archivarán los que no usas. + Puedes tener 200 packs de stickers activos.\nSi añades más, se archivarán los que no usas. Puedes añadir hasta 200 packs de máscaras.\nSi añades más, se archivarán los que no usas. ENVIAR STICKER Stickers archivados @@ -1758,7 +1782,7 @@ Tamaño máximo de video Tamaño máximo de archivo Precargar siguiente audio - Comienza a descargar el siguiente tema mientras estás escuchando un archivo de audio. + Comienza la descarga de la siguiente pista mientras estás escuchando un audio. Precargar videos grandes Precarga los primeros segundos (1-2 MB) de videos que superan los %1$s para su reproducción instantánea. Actívalo si quieres que la multimedia se descargue automáticamente con datos móviles. @@ -1814,6 +1838,10 @@ Sonidos en el chat Por defecto Por defecto + Por defecto + Por defecto en la app + %1$s en la app + Silenciadas Notificaciones inteligentes Excepciones Añadir una excepción @@ -1831,9 +1859,9 @@ Las vistas previas serán generadas en los servidores de Telegram. No almacenamos datos sobre los enlaces que envías. Chats secretos Navegador en la app - Abrir enlaces externos en la app + Abre enlaces externos en la app Direct Share - Ver chats recientes al compartir en Android + Ve chats recientes al compartir en Android Emoji Emojis grandes Usar emoji predeterminado @@ -1960,7 +1988,7 @@ Calculando... Archivos Fotos - Mensajes de voz/video + Mensajes de voz y video Videos Música GIF @@ -2160,19 +2188,19 @@ vietnamita Sesiones activas - Sesión actual + Este dispositivo Sin otras sesiones activas Puedes iniciar sesión en Telegram desde otro móvil, tablet o computadora, usando el mismo número de teléfono. Todos tus datos se sincronizarán al instante. Sesiones activas Controla tus sesiones en otros dispositivos. - Toca una sesión para cerrarla. + Toca en una sesión para cerrarla. ¿Cerrar esta sesión? ¿Quieres cerrar esta sesión? - Salir de todos los dispositivos, excepto este. + Sale de todos los dispositivos, excepto este. Cerrar sesiones Cerrar sesión Cerrar - ¿Quieres terminar todas las demás sesiones? + ¿Quieres cerrar todas las demás sesiones? Cerrar todas las demás sesiones app no oficial Sin sesiones activas. @@ -2230,7 +2258,7 @@ Bots Añadiendo chats Espera un momento mientras llenamos esta carpeta… - No se encontraron chats + La carpeta está vacía Actualmente no hay chats que\npertenezcan a esta carpeta. Nueva carpeta Sin chats @@ -2417,12 +2445,12 @@ Ya estás a menos de %1$s Compartir ubicación Compartir - Para que funcione el aviso, por favor, comparte tu ubicación en tiempo real en este chat. + Para que funcione el aviso, comparte tu ubicación en tiempo real en este chat. Avisar cuando %1$s esté cerca Avisar cuando otros miembros del grupo estén cerca - Aviso de proximidad activo + Aviso de proximidad establecido Te notificaremos cuando %1$s esté a %2$s de ti. - We will notify you once someone is within %1$s from you. + Te notificaremos cuando alguien esté a %1$s de ti. Aviso de proximidad cancelado Mostrar como lista @@ -2570,12 +2598,13 @@ Verificación en dos pasos Verificación en dos pasos ¡Contraseña establecida! - Esta contraseña será requerida cuando inicies sesión en un nuevo dispositivo, además del código recibido vía SMS. + Esta contraseña se te solicitará al iniciar sesión en un nuevo dispositivo, además del código recibido vía SMS. Volver a Ajustes Volver a Passport Crear contraseña + Show password Poner contraseña adicional - Puedes poner una contraseña, que será requerida cuando inicies sesión en un nuevo dispositivo, además del código que recibes vía SMS. + Puedes poner una contraseña que se te solicitará al iniciar sesión en un nuevo dispositivo, además del código que recibes vía SMS. Tu contraseña Activada Desactivada @@ -2630,7 +2659,7 @@ Código de recuperación Enviamos un código de recuperación al correo que nos diste:\n\n%1$s Por favor, revisa tu correo y pon el código de 6 dígitos que te enviamos. - ¿Tienes problemas para acceder a tu correo %1$s? + ¿No puedes acceder a %1$s? ¿Tienes problemas para acceder a tu correo? Si no puedes acceder a tu correo, las opciones restantes son recordar tu contraseña o restablecer tu cuenta. RESTABLECER MI CUENTA @@ -2654,6 +2683,7 @@ Uso de almacenamiento y red Uso de almacenamiento Uso de datos + Ruta de almacenamiento Móvil Wi-Fi Itinerancia @@ -2676,8 +2706,8 @@ Privacidad y seguridad Privacidad Última vez y en línea - Foto de perfil - ¿Quién puede ver mi foto de perfil? + Fotos de perfil + ¿Quién puede ver mis fotos y videos de perfil? Puedes restringir quién puede ver tu foto de perfil con gran precisión. Puedes añadir usuarios o grupos como excepciones que anularán los ajustes de arriba. Número de teléfono @@ -2852,6 +2882,14 @@ un1 ahora está a %1$s de ti Ahora estás a %1$s de un1 un1 ahora está a %1$s de un2 + un1 te añadió a este grupo + un1 te añadió a este canal + un1 inició el chat de voz + Iniciaste el chat de voz + Chat de voz finalizado (%s) + un1 invitó a un2 al chat de voz + Invitaste a un2 al chat de voz + un1 te invitó al chat de voz Autorizaste que este bot te envíe mensajes cuando iniciaste sesión en %1$s. %1$s recibió los siguientes documentos: %2$s Datos personales @@ -2867,7 +2905,7 @@ Contrato de alquiler Número de teléfono Dirección de correo - Tu versión de Telegram no es compatible con este mensaje. Por favor, actualiza tu app para verlo: https://telegram.org/update + Tu versión de Telegram no es compatible con este mensaje. Actualiza tu app para verlo: https://telegram.org/update Foto Video Foto con autodestrucción @@ -2910,7 +2948,7 @@ Código expirado. Por favor, vuelve a iniciar sesión. Demasiados intentos. Por favor, reinténtalo más tarde. Demasiados intentos. Por favor, reinténtalo en %1$s - Código inválido + Código inválido. Por favor, reinténtalo. Has eliminado y vuelto a crear tu cuenta muchas veces recientemente. Por favor, espera algunos días antes de registrarte de nuevo. Nombre inválido Lo sentimos, este apellido no se puede usar @@ -2946,7 +2984,7 @@ ¿Quieres eliminar el chat con **%1$s**? ¿Quieres eliminar el chat con **%1$s** y bloquearlo? ¿Quieres eliminar **Mensajes guardados**? - ¿Quieres eliminar el chat secreto con **%1$s**? + ¿Quieres eliminar tu chat secreto con **%1$s**? ¿Quieres eliminar el chat **%1$s**? Eliminar borradores ¿Quieres eliminar todos los borradores en la nube? @@ -2991,8 +3029,8 @@ ¿Quieres enviar este contacto a **%1$s**? No hay ninguna cuenta de Telegram con este nombre de usuario. Este bot no puede unirse a grupos. - ¿Quieres permitir las vistas previas ampliadas en chats secretos? Ten en cuenta que son generadas en los servidores de Telegram. - Ten en cuenta que los bots integrados son hechos por terceros. Para que funcione, los símbolos escritos después del nombre de usuario del bot son enviados al desarrollador respectivo. + ¿Quieres activar las vistas previas de enlaces ampliadas en los chats secretos? Ten en cuenta que son generadas en los servidores de Telegram. + Ten en cuenta que los bots integrados son hechos por terceros. Para que el bot funcione, los símbolos escritos después del nombre de usuario del bot son enviados a su respectivo desarrollador. Lo sentimos, no puedes editar este mensaje. Por favor, permite a Telegram recibir llamadas para que podamos ingresar automáticamente el código por ti. Por favor, permite a Telegram recibir llamadas y leer el registro de llamadas para que podamos poner automáticamente el código por ti. @@ -3026,9 +3064,12 @@ Telegram necesita acceso a tu ubicación para que puedas compartirla con tus amigos. Telegram necesita acceso a tu ubicación. Telegram necesita acceso a mostrarse sobre otras aplicaciones para usar el modo imagen en imagen. + El modo de superposición te permite usar la opción de pulsar para hablar y ver quién está hablando aunque estés fuera de Telegram. AJUSTES Por favor, permite a Telegram aparecer en la pantalla bloqueada para que las llamadas funcionen correctamente. Para compartir tu ubicación en tiempo real en este chat, Telegram necesita acceso a tu ubicación todo el tiempo, incluyendo cuando la app está en segundo plano.\n\nAccederemos a tu ubicación sólo durante el tiempo que elijas, y puedes dejar de compartirla en cualquier momento. No usaremos tu ubicación para ningún otro propósito que no sea el de compartirla en este chat. + Modo imagen en imagen + Superposición del chat de voz Crecimiento Seguidores @@ -3127,23 +3168,28 @@ Empezar a chatear Ajustes de la cuenta - Usar menos datos + Menos datos en llamadas Llamada entrante Conectando Intercambiando claves de cifrado Esperando Solicitando Colgando - Llamada terminada + Llamada finalizada Conexión fallida Llamando Línea ocupada Llamada de Telegram Videollamada de Telegram Llamada de Telegram en curso + Chat de voz en curso Finalizar Otra llamada en curso - Actualmente tienes una llamada en curso con **%1$s**. ¿Quieres colgar y empezar una nueva con **%2$s**? + ¿Quieres finalizar la llamada con **%1$s** e iniciar una nueva con **%2$s**? + ¿Quieres finalizar la llamada con **%1$s** e iniciar el chat de voz en **%2$s**? + Hay otro chat de voz en curso + ¿Quieres salir del chat de voz en **%1$s** e iniciar uno nuevo en **%2$s**? + ¿Quieres salir del chat de voz en **%1$s** y llamar a **%2$s**? Llamadas Tono de llamada Puedes personalizar el tono de llamada desde este contacto en Telegram. @@ -3160,7 +3206,9 @@ Contestar Rechazar Estás sin conexión. Por favor, conéctate a internet para realizar llamadas. + Estás sin conexión. Conéctate a internet para que puedas unirte a chats de voz. Tienes activado el modo avión. Por favor, desactívalo o conéctate a una red Wi-Fi para realizar llamadas. + Tienes el modo avión activado. Desactívalo o conéctate a una red Wi-Fi para unirte a chats de voz. Sin conexión Modo avión Ajustes @@ -3175,7 +3223,7 @@ Videollamada cancelada Videollamada rechazada %1$s (%2$s) - Aún no has realizado llamadas. + Aún no hay llamadas... La app de **%1$s** está usando un protocolo incompatible. Necesita actualizar la app para poder llamar. La app de **%1$s** no es compatible con las llamadas. Necesita actualizar su app para recibir tu llamada. Lo sentimos, **%1$s** está usando una versión antigua de Telegram que no permite hacer videollamadas. @@ -3204,7 +3252,7 @@ Esto no revela los contenidos de tu chat y nos ayuda a resolver el problema antes. Gracias por ayudarnos a mejorar las llamadas de Telegram. contestando como %s - Responder con mensaje + Responder con un mensaje Estas respuestas rápidas estarán disponibles cuando respondas a una llamada entrante con un mensaje de Telegram. Puedes modificarlas para decir lo que tú quieras. No puedo hablar ahora. ¿Qué pasa? Te llamaré enseguida. @@ -3226,6 +3274,11 @@ El video estaba pixelado Toca aquí para encender tu cámara No silenciar + o mantén para hablar + Estás en directo + Silenciado por el administrador + Silenciado + Estás en modo de sólo escucha Silenciar Iniciar video Detener video @@ -3244,6 +3297,61 @@ ¿Quieres videollamar a **%1$s**? Videollamada Reconectando + Iniciar chat de voz + Chat de voz + ¿Quieres iniciar el chat de voz? + Gestionar chats de voz + Unirme + %1$s miembros hablando + %1$s miembro hablando + %1$s miembros hablando + %1$s miembros hablando + %1$s miembros hablando + %1$s miembros hablando + hablando + escuchando + invitado + Salir + Finalizar + Silenciar micrófono + ¿Quieres silenciar a **%1$s** en este chat de voz? + Eliminar miembro + ¿Quieres eliminar a %1$s del grupo? + **%1$s** fue eliminado del grupo. + **%1$s** ahora puede hablar. + **%1$s** fue silenciado en este chat. + Silenciar + Los nuevos pueden hablar + Los nuevos son silenciados + Compartir enlace de invitación + Finalizar chat de voz + Conectando… + Salir del chat de voz + ¿Quieres salir de este chat de voz? + Finalizar chat de voz + ¿Quieres finalizar este chat de voz? + Finalizar chat de voz + VER CHAT DE VOZ + Chat de voz + Abrir chat de voz + El usuario elegido ya está en este chat de voz. + Lo sentimos, no puedes unirte a chats de voz como administrador anónimo. + un1 invitó a un2 al chat de voz + Unirme al chat de voz + ¡Oye! Únete a nuestro chat de voz: %1$s + Invitar miembros + Eliminar + Permitirle hablar + Buscar miembros para invitar... + Copiar enlace de invitación + Enlace de invitación copiado al portapapeles. + Toca para activar + Chat de voz finalizado. ¿Quieres iniciar uno nuevo? + Añadir miembro + ¿Quieres añadir a **%1$s** a **%2$s**? + Invitaste a **%1$s** al chat de voz. + Añadir + Toca para unirte Mensaje al %1$s Llamada de voz al %1$s @@ -3327,6 +3435,12 @@ %1$d miembros %1$d miembros %1$d miembros + %1$d participantes + %1$d participante + %1$d participantes + %1$d participantes + %1$d participantes + %1$d participantes y %1$d más están escribiendo y %1$d más están escribiendo y %1$d más están escribiendo @@ -3346,7 +3460,7 @@ %1$d mensajes nuevos %1$d mensajes nuevos %1$d mensajes desfijados - mensaje desfijado + Mensaje desfijado %1$d mensajes desfijados %1$d mensajes desfijados %1$d mensajes desfijados @@ -3507,12 +3621,12 @@ %1$s reenvíos %1$s reenvíos %1$s reenvíos - %1$s reenvíos públicos - %1$s reenvío público - %1$s reenvíos públicos - %1$s reenvíos públicos - %1$s reenvíos públicos - %1$s reenvíos públicos + %1$s reenvíos en público + %1$s reenvío en público + %1$s reenvíos en público + %1$s reenvíos en público + %1$s reenvíos en público + %1$s reenvíos en público %1$s reenvíos %1$s reenvío %1$s reenvíos @@ -3746,11 +3860,14 @@ Grupo Canal Chat secreto - Enviado el %s + Enviado %s Recibido el %s Programado para el %s Volver atrás Abrir menú de navegación + Abrir menú + Cerrar menú + Open in photo viewer %2$s por %1$s Más opciones Reproducir @@ -3898,4 +4015,5 @@ \'Recordar hoy a las\' HH:mm \'Recordar el\' d \'de\' MMM \'a las\' HH:mm \'Recordar el\' d \'de\' MMM \'de\' yyyy \'a las\' HH:mm + Activar diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 3e8e66a12fc..7fa118a5acd 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -39,7 +39,7 @@ Annulla ripristino account Qualcuno con accesso a **%1$s** ha richiesto l\'eliminazione del tuo account Telegram e il ripristino della password della verifica in due passaggi.\n\nSe non sei stato tu, per favore inserisci il codice che abbiamo appena inviato tramite SMS. Puoi anche annullare *cambiando il tuo numero di telefono*. Ripristino account - Dato che l\'account **%1$s** è attivo e protetto da una password, lo elimineremo tra 1 settimana per motivi di sicurezza.\n\nPuoi annullare questo processo in qualsiasi momento. + Dato che l\'account **%1$s** è attivo e protetto da una password, sarà eliminato tra 1 settimana. Questo ritardo è richiesto per motivi di sicurezza.\n\nPuoi annullare questo processo in qualsiasi momento. Potrai ripristinare il tuo account tra: I tuoi tentativi recenti di ripristinare questo account sono stati annullati dal suo utente attivo. Per favore riprova tra 7 giorni. RIPRISTINA ACCOUNT @@ -53,8 +53,8 @@ Cognome (facoltativo) Annulla iscrizione - Hai appena trasferito con successo %1$s a %2$s per %3$s - Hai appena trasferito con successo %1$s a %2$s + Hai trasferito con successo %1$s a %2$s per %3$s + Hai trasferito con successo %1$s a %2$s Cassa Metodi di spedizione Spiacenti, non è possibile consegnare al tuo indirizzo. @@ -165,6 +165,7 @@ Fissa Togli Archivia + Archivio Estrai Chat archiviate Elimina chat @@ -172,7 +173,7 @@ Seleziona chat Inoltra a... Foto segreta - Video segreto + Video temporaneo GIF segreta %1$s sta usando una versione vecchia di Telegram, quindi le foto segrete saranno visualizzate in modalità di compatibilità.\n\nUna volta che %2$s avrà aggiornato Telegram, le foto con il timer minore di 1 minuto funzioneranno in modalità \'Tieni premuto per vedere\' , e sarai notificato ogni volta che l\'altro esegue uno screenshot. Messaggi @@ -181,7 +182,7 @@ Silenzia per %1$s Suona Tra %1$s - Silenzia per sempre + Disattiva HASHTAG Recenti Persone @@ -267,10 +268,10 @@ Sei sicuro di voler lasciare **%1$s**? Spiacenti, non puoi aggiungere questo utente ai gruppi. Spiacenti, questo gruppo è pieno. - Spiacenti, se una persona non fa più parte di un gruppo, devi essere nei suoi contatti di Telegram per poterla aggiungere di nuovo.\n\nTieni presente che può comunque partecipare tramite link di invito del gruppo purché non sia nell\'elenco Utenti rimossi. + Spiacenti, se una persona non fa più parte di un gruppo, devi essere nei suoi contatti di Telegram per poterla riaggiungere.\n\nTieni presente che può comunque unirsi con il link d\'invito del gruppo purché non sia nell\'elenco Utenti rimossi. Spiacenti, troppi amministratori in questo gruppo. - Spiacenti, l\'utente in oggetto ha già troppi gruppi o canali pubblici. Per favore chiedigli di rendere privato uno dei suoi gruppi o canali. - Spiacenti, l\'utente in oggetto ha già troppi gruppi basati sulla posizione. Per favore chiedigli di eliminare o trasferire prima uno di quelli. + Spiacenti, l\'utente selezionato ha già troppi gruppi o canali pubblici. Per favore chiedigli di rendere privato uno dei suoi gruppi o canali. + Spiacenti, l\'utente selezionato ha già troppi gruppi basati sulla posizione. Per favore chiedigli di eliminarne o trasferirne uno prima. Spiacenti, hai già troppi gruppi basati sulla posizione. Per favore eliminane prima uno dei tuoi. Spiacenti, troppi bot in questo gruppo. un1 ha fissato \"%1$s\" @@ -295,7 +296,7 @@ Gli utenti rimossi dal canale dagli amministratori non possono rientrare tramite link d\'invito. Nuovo canale Nome del canale - Aggiungi contatti al tuo canale + Aggiungi persone al tuo canale Se imposti un link permanente, le altre persone potranno trovare il tuo canale e unirsi.\n\nPuoi usare a-z, 0-9 e underscore.\nLa lunghezza minima è 5 caratteri. Se imposti un link permanente, le altre persone potranno trovare il tuo gruppo e unirsi.\n\nPuoi usare a-z, 0-9 e underscore.\nLa lunghezza minima è 5 caratteri. Attenzione @@ -371,7 +372,7 @@ Video del canale cambiato Foto del canale rimossa Nome del canale cambiato in un2 - Spiacenti, hai riservato troppi username pubblici. Puoi revocare il link da uno dei tuoi gruppi o canali più vecchi, o creare invece delle entità private. + Hai riservato troppi link pubblici. Prova a revocare il link da un gruppo o canale più vecchio, oppure creane uno privato. Proprietario Amministratore Amministratore @@ -380,7 +381,7 @@ Aggiungi amministratore Rimuovi utente Sblocca - Tieni premuto sull\'utente per sbloccarlo. + Tieni premuto l\'utente per sbloccarlo. Invita tramite link Rimuovi amministratore Modifica permessi @@ -393,11 +394,11 @@ Sfortunatamente, non ti è permesso partecipare ai gruppi pubblici. Spiacenti, questa chat non è più accessibile. Aggiungere %1$s al canale? - Spiacenti, se una persona non fa più parte di un canale, devi essere nei suoi contatti di Telegram per poterla aggiungere di nuovo.\n\nTieni presente che può comunque partecipare tramite link di invito del canale purché non sia nell\'elenco Utenti rimossi. + Spiacenti, se una persona non fa più parte di un canale, devi essere nei suoi contatti di Telegram per poterla riaggiungere.\n\nTieni presente che può comunque unirsi con il link d\'invito del canale purché non sia nell\'elenco Utenti rimossi. Spiacenti, non puoi aggiungere questo utente ai canali. Spiacenti, troppi amministratori in questo canale. Spiacenti, troppi bot in questo canale. - Spiacenti, puoi aggiungere solo i primi 200 membri a un canale. Ricorda che un numero illimitato di persone potrebbe unirsi tramite il link del canale. + Spiacenti, puoi aggiungere solo i primi 200 iscritti a un canale. Ricorda che un numero illimitato di persone può unirsi con il link del canale. Troppe community Spiacenti, sei membro di troppi gruppi e canali. Per favore lasciane qualcuno prima di crearne uno nuovo. Spiacenti, sei membro di troppi gruppi e canali. Per favore lasciane qualcuno prima di unirti ad uno. @@ -444,7 +445,7 @@ Eliminare messaggi altrui Eliminare messaggi Aggiungere amministratori - Inviare anonimamente + Rimanere anonimo Rimuovi amministratore Trasferisci proprietà gruppo Trasferisci proprietà canale @@ -457,8 +458,8 @@ Imposta password Questo trasferirà tutti i **diritti di proprietà** per **%1$s** a **%2$s**. Cambia proprietario - **%1$s** è ora il proprietario del gruppo. - **%1$s** è ora il proprietario del canale. + **%1$s** ora è il proprietario del gruppo. + **%1$s** ora è il proprietario del canale. Bloccare utenti Aggiungere utenti Invitare utenti tramite link @@ -475,7 +476,7 @@ Inviare messaggi Inviare media Inviare sondaggi - Inviare stickers e GIF + Inviare sticker e GIF Inviare link con anteprima Cambiare le info chat Fissare messaggi @@ -503,7 +504,7 @@ Imposta nuova foto Imposta foto o video Visibile - I nuovi membri vedranno i messaggi che sono stati inviati prima che si unissero. + I nuovi membri vedranno i messaggi inviati prima di unirsi. Nascosta I nuovi membri non vedranno i messaggi precedenti. I nuovi membri non vedranno più di 100 messaggi precedenti. @@ -531,7 +532,7 @@ Ricerca web Statistiche I bot possono essere aggiunti solo come amministratori - Spiacenti, i bot possono essere aggiunti ai canali solo come amministratori. + I bot possono essere aggiunti ai canali solo come amministratori. RENDI AMMINISTRATORE %1$s sarà rimosso dagli amministratori se lo limiti. Discussione @@ -541,7 +542,7 @@ Seleziona una chat di gruppo che ospiterà i commenti dal tuo canale. Tutto ciò che pubblichi nel canale verrà inoltrato in questo gruppo. **%1$s** è il gruppo che sarà usato per ospitare i commenti per il tuo canale. - Il gruppo è collegato come chat di discussione di **%1$s**. + Il gruppo è collegato come chat di discussione di %1$s. Tutti i nuovi messaggi pubblicati in questo canale sono inoltrati nel gruppo. Crea un nuovo gruppo Scollega gruppo @@ -567,6 +568,7 @@ La modalità lenta è attiva. Non puoi selezionare più elementi. Spiacenti, questo testo è troppo lungo da inviare come singolo messaggio.\n\nLa modalità lenta è attiva. Non puoi inviare più di un messaggio alla volta. **%1$s** promosso ad amministratore + **%1$s** rimosso da **%2$s** Nuovo sondaggio Nuovo quiz @@ -639,14 +641,14 @@ Azioni recenti Tutte le azioni - Azioni selezionate + azioni selezionate Tutti gli amministratori **Ancora nessuna azione**\n\nI membri e gli amministratori del\ngruppo non hanno eseguito azioni\ndi servizio nelle ultime 48 ore. **Ancora nessuna azione**\n\nGli amministratori del canale non\nhanno eseguito azioni di servizio\nnelle ultime 48 ore. **Nessuna azione trovata**\n\nNon sono state trovate azioni recenti\nche rispondono alla tua richiesta. Non sono state trovate azioni recenti contenenti \'**%1$s**\' . Cosa sono le azioni recenti? - Questa è una lista di tutte le azioni di servizio effettuate dai membri e dagli amministratori del gruppo nelle ultime 48 ore. + Questa è una lista delle azioni importanti da parte di membri e amministratori nelle ultime 48 ore. Questa è una lista di tutte le azioni di servizio eseguite dagli amministratori del canale nelle ultime 48 ore. un1 ha rinominato il gruppo in \"%1$s\" un1 ha rinominato il canale in \"%1$s\" @@ -716,8 +718,9 @@ Modificare messaggi Eliminare messaggi Aggiungere amministratori - Invia anonimamente + Rimani anonimo Bloccare utenti + Gestire chat vocali Aggiungere utenti Titolo: %1$s Titolo @@ -732,8 +735,15 @@ Messaggi modificati Messaggi fissati Membri usciti - un1 ha attivato la modalità lenta con timer %1$s + Chat vocali + un1 ha impostato la modalità lenta a %1$s un1 ha disattivato la modalità lenta + un1 ha iniziato una chat vocale + un1 ha terminato la chat vocale + un1 ha silenziato un2 in una chat vocale + un1 ha riattivato un2 in una chat vocale + un1 ha permesso ai nuovi partecipanti della chat vocale di parlare + un1 ha silenziato i nuovi partecipanti della chat vocale Nuova lista broadcast Inserisci il nome della lista @@ -749,7 +759,7 @@ Musica Artista sconosciuto Titolo sconosciuto - Ripeti canzone + Ripeti traccia Ripeti lista Lista casuale Inverti ordine @@ -824,7 +834,7 @@ File Foto Ancora nessun messaggio... - Ancora nessun messaggio programmato qui... + Ancora nessun messaggio programmato... Messaggio inoltrato Da Da %1$s @@ -852,7 +862,7 @@ SCORRI PER ANNULLARE Salva nei download Salva nelle GIF - Eliminare la GIF? + Eliminare la GIF da questa sezione? Salva nella musica Condividi Applica traduzione @@ -904,7 +914,7 @@ Fissa messaggio Togli messaggio Vuoi fissare un vecchio messaggio lasciandone fissato uno più recente? - Vuoi fissare questo messaggio per tutti i membri del gruppo? + Fissare questo messaggio nel gruppo? Vuoi fissare questo messaggio in questo canale? Vuoi fissare questo messaggio nella parte superiore della chat? Vuoi togliere questo messaggio? @@ -935,6 +945,13 @@ Modifica messaggio Modifica didascalia Tocca per modificare + Modifica foto + Modifica video + Cambia foto + Cambia video + Cambia media + Cambia file + Cambia file audio Scorri in basso per i bot %1$s Spiacenti, tempo di modifica scaduto. @@ -1003,6 +1020,8 @@ Tocca per le foto, tieni premuto per i video Tocca per vedere come lista. Invia senza suono + Invia come nuova foto + Sostituisci foto Invia ora Riprogramma Oggi @@ -1052,13 +1071,13 @@ Trasferisci proprietà bot Questo trasferirà tutti i **diritti di proprietà** per il bot all\'utente selezionato. Cambia proprietario - Puoi trasferire il bot solo se hai: + Puoi trasferire questo bot solo se hai: Lascia un commento Commenti Commenta Risposte - Ancora nessun commento qui... - Ancora nessuna risposta qui... + Ancora nessun commento... + Ancora nessuna risposta... Visualizza in chat Invia anonimamente Discussione iniziata @@ -1116,7 +1135,7 @@ %1$s ha inviato un file nel gruppo %2$s %1$s ha inviato una GIF nel gruppo %2$s %1$s ha inviato una fattura nel gruppo %2$s per %3$s - %1$s ha inviato un messaggio vocale nel gruppo %2$s + %1$s ha inviato un messaggio vocale a %2$s %1$s ha inviato un videomessaggio nel gruppo %2$s %1$s ha inviato un file audio nel gruppo %2$s %1$s ha inviato uno sticker nel gruppo %2$s @@ -1126,13 +1145,17 @@ %1$s ha modificato la foto del gruppo %2$s %1$s ha cambiato il video del gruppo per %2$s %1$s ha invitato %3$s nel gruppo %2$s + %1$s ha invitato %3$s in una chat vocale in %2$s + %1$s ti ha invitato in una chat vocale in %2$s + %1$s ha iniziato una chat vocale in %2$s + %1$s ha terminato la chat vocale in %2$s %1$s è tornato nel gruppo %2$s %1$s si è unito al gruppo %2$s %1$s ha rimosso %3$s dal gruppo %2$s %1$s ti ha rimosso dal gruppo %2$s %1$s ha lasciato il gruppo %2$s %1$s si è unito a Telegram! - %1$s,\nAbbiamo rilevato un accesso al tuo account da un nuovo dispositivo il %2$s\n\nDispositivo: %3$s\nPosizione: %4$s\n\nSe non sei stato tu, puoi andare in Impostazioni - Privacy e sicurezza - Sessioni - Termina tutte le sessioni.\n\nSe pensi che qualcuno si sia collegato al tuo account contro il tuo volere, puoi attivare la verifica in due passaggi nelle impostazioni di Privacy e sicurezza.\n\nCordiali saluti,\nil team di Telegram + %1$s,\nAbbiamo rilevato un accesso al tuo account da un nuovo dispositivo il %2$s\n\nDispositivo: %3$s\nPosizione: %4$s\n\nSe non sei stato tu, puoi andare in Impostazioni > Dispositivi e terminare quella sessione.\n\nSe pensi che qualcuno si sia collegato al tuo account contro il tuo volere, puoi attivare la Verifica in due passaggi nelle impostazioni di Privacy e sicurezza.\n\nCordiali saluti,\nil team di Telegram %1$s ha aggiornato la foto del profilo %1$s si è unito al gruppo %2$s tramite link d\'invito %1$s ha inviato %3$s nel gruppo %2$s @@ -1158,7 +1181,7 @@ %1$s ha fissato un file nel gruppo %2$s %1$s ha fissato uno sticker nel gruppo %2$s %1$s ha fissato uno %3$s sticker nel gruppo %2$s - %1$s ha fissato un messaggio vocale nel gruppo %2$s + %1$s ha fissato un messaggio vocale in %2$s %1$s ha fissato un videomessaggio nel gruppo %2$s %1$s ha fissato un contatto %3$s nel gruppo %2$s %1$s ha fissato una posizione nel gruppo %2$s @@ -1212,7 +1235,7 @@ Condividi contatto Aggiungi contatto Ancora nessun contatto - Ehi, sto usando Telegram per messaggiare. Unisciti a me! Scaricalo qui: %1$s + Ehi, sto usando Telegram per chattare. Unisciti a me! Scaricalo qui: %1$s alle ieri alle alle %1$s @@ -1242,7 +1265,7 @@ Numero di telefono Non hai ancora contatti su Telegram Invita gli amici a provare Telegram - Trova persone nelle vicinanze con cui messaggiare + Trova persone nelle vicinanze con cui chattare Cerca persone tramite username Nuovo contatto Il numero di telefono **%1$s** non è tra i tuoi contatti. Vuoi aggiungerlo? @@ -1262,13 +1285,14 @@ UNISCITI Link copiato negli appunti Link copiato negli appunti.\nQuesto link funzionerà solo per i membri di questa chat. + This link will only work for members of this chat. Sfortunatamente, non puoi accedere a questo messaggio. Non sei membro della chat in cui è stato pubblicato. Numero copiato negli appunti Email copiata negli appunti Invita nel gruppo tramite link Link d\'invito Sei sicuro di voler revocare questo link? Una volta fatto, nessuno potrà unirsi utilizzandolo. - Il precedente link d\'invito è ora inattivo. Ne è stato creato uno nuovo. + Il precedente link d\'invito ora è inattivo. Ne è stato creato uno nuovo. Revoca Revoca link Sei sicuro di voler revocare il link **%1$s**?\n\nIl gruppo \"**%2$s**\" diventerà privato. @@ -1284,7 +1308,7 @@ Impostazioni Aggiungi iscritto Aggiungi membro - Imposta amministratori + Aggiungi amministratori RIMUOVI DAL GRUPPO Elimina e lascia il gruppo Elimina e lascia il gruppo @@ -1296,7 +1320,7 @@ Converti in supergruppo Attenzione Questa azione è irreversibile. Non è possibile trasformare un supergruppo in un gruppo normale. - **Limite membri raggiunto.**\n\nPer superare il limite e sbloccare nuove funzioni, aggiorna a supergruppo:\n\n• I supergruppi hanno massimo %1$s\n• I nuovi membri vedono tutta la cronologia\n• I messaggi eliminati scompaiono per tutti\n• Gli admin possono aggiungere una descrizione al gruppo\n• Il creatore può creare un link pubblico per il gruppo + **Limite membri raggiunto.**\n\nPer avere maggiore spazio e funzioni aggiuntive, aggiorna a supergruppo:\n\n• I supergruppi hanno massimo %1$s\n• I nuovi membri possono vedere tutta la cronologia\n• I messaggi eliminati scompaiono per tutti\n• Gli admin possono aggiungere una descrizione al gruppo\n• Il proprietario può creare un link pubblico per il gruppo **Nei supergruppi:**\n\n• I nuovi membri vedono tutta la cronologia\n• I messaggi eliminati scompaiono per tutti\n• Gli admin possono aggiungere una descrizione al gruppo\n• Il creatore può creare un link pubblico per il gruppo **Nota:** questa azione non può essere annullata. @@ -1332,7 +1356,7 @@ Aggiungi qualche riga su di te Nessuna Puoi aggiungere qualche riga su di te. Chiunque apra il tuo profilo vedrà questo testo. - Inizia chat segreta + Avvia chat segreta Gruppi in comune Gruppi in comune Nessun gruppo in comune @@ -1350,7 +1374,7 @@ Il numero di telefono sarà visibile dopo che %1$s ti avrà aggiunto come contatto. Quando premerai su **FATTO**, il tuo numero di telefono sarà visibile a %1$s. Condividi il mio numero con %1$s - %1$s è ora nella tua lista contatti + %1$s ora è nella tua lista contatti Info Telefono Contenuto condiviso @@ -1366,8 +1390,8 @@ Spiacenti, questo username non è valido. Un username deve avere almeno 5 caratteri. Il massimo per un username è 32 caratteri. - Spiacenti, un username non può iniziare con un numero. - Puoi scegliere un username su **Telegram**. Se lo fai, le altre persone potranno trovarti tramite questo username e contattarti senza conoscere il tuo numero di telefono.\n\nPuoi usare **a–z**, **0–9** e underscore. La lunghezza minima è **5** caratteri. + Gli username non possono iniziare con un numero. + Puoi scegliere un username su **Telegram**. Se lo fai, le persone potranno trovarti tramite questo username e contattarti senza aver bisogno del tuo numero di telefono.\n\nPuoi usare **a–z**, **0–9** e underscore. La lunghezza minima è **5** caratteri. Questo link apre una chat con te:\n%1$s Controllo l\'username... %1$s è disponibile. @@ -1392,7 +1416,7 @@ Sticker del gruppo Altri sticker Elimina dai preferiti - Elimina dai recenti + Rimuovi dai recenti Aggiungi alle maschere Sticker non trovati Sticker rimossi @@ -1435,7 +1459,7 @@ Maschere archiviate Nessuno sticker archiviato Nessuna maschera archiviata - Puoi aggiungere fino a 200 set di sticker.\nI set non usati saranno archiviati quando ne aggiungerai altri. + Puoi avere 200 set di sticker attivi.\nI set non usati sono archiviati quando ne aggiungi altri. Puoi aggiungere fino a 200 set di maschere.\nI set non usati saranno archiviati quando ne aggiungerai altri. INVIA STICKER Sticker archiviati @@ -1814,6 +1838,10 @@ Suoni in-chat Default Default + Default + Default in-app + %1$s in-app + Silenzioso Notifiche intelligenti Eccezioni Aggiungi eccezione @@ -1838,7 +1866,7 @@ Emoji grandi Usa emoji di default Telegram per Android %1$s - Menù debug + Menu debug Invia i log \nCancella i log Attiva i log @@ -1876,7 +1904,7 @@ Proxy MTProto Il proxy che stai usando non è configurato correttamente e sarà disattivato. Per favore trovane un altro. Sponsor del proxy - Questo canale è mostrato dal tuo server proxy. Per rimuovere questo canale dalla tua lista chat, disattiva il proxy nelle Impostazioni di Telegram. + Questo canale è mostrato dal tuo server proxy. Per rimuovere il canale dalla lista chat, disattiva il proxy nelle Impostazioni di Telegram. Impostazioni proxy SOCKS5 Impostazioni proxy MTProto. Questo proxy potrebbe mostrare un canale sponsorizzato nella tua lista chat. Questo non rivela nulla del tuo traffico Telegram. @@ -1960,7 +1988,7 @@ Calcolo... Documenti Foto - Messaggi vocali/video + Vocali e videomessaggi Video Musica GIF @@ -2030,7 +2058,7 @@ Per favore inserisci il codice di conferma che abbiamo appena inviato a %1$s. Per favore inserisci la tua password per accedere ai tuoi dati personali. %1$s richiede l\'accesso ai tuoi dati personali per l\'iscrizione ai suoi servizi. - Per favore inserisci la tua password di Telegram per decifrare i tuoi dati. + Inserisci la tua password di Telegram per decifrare i tuoi dati. Accetti l\'*Informativa sulla privacy di %1$s* e consenti a @%2$s di inviarti messaggi. Stai inviando i tuoi documenti direttamente a %1$s e autorizzi il loro @%2$s a inviarti messaggi. AUTORIZZA @@ -2160,9 +2188,9 @@ Vietnamita Sessioni attive - Sessione attuale + Questo dispositivo Nessun\'altra sessione attiva - Ti puoi connettere a Telegram da altri dispositivi mobili, tablet e desktop usando lo stesso numero. Tutti i tuoi dati saranno sincronizzati istantaneamente. + Puoi accedere a Telegram da altri dispositivi mobile, tablet e desktop usando lo stesso numero. Tutti i tuoi dati saranno sincronizzati istantaneamente. Sessioni attive Controlla le tue sessioni sugli altri dispositivi. Tocca su una sessione per terminarla. @@ -2230,7 +2258,7 @@ Bot Aggiungo le chat Per favore attendi qualche momento mentre riempiamo questa cartella per te... - Nessuna chat trovata + La cartella è vuota Al momento non ci sono chat nella cartella. Nuova cartella Nessuna chat @@ -2411,7 +2439,7 @@ Imposta questa posizione Le persone potranno trovare il tuo gruppo nella sezione \"Persone vicine\". Luoghi in quest\'area - Notifica di prossimità + Avviso di prossimità Notifica quando %1$s è a %2$s Notifica quando qualcuno è a %1$s Sei già più vicino di %1$s @@ -2420,10 +2448,10 @@ Per far funzionare l\'avviso, condividi la posizione in tempo reale in questa chat. Avvisa quando %1$s è vicino Avvisa quando gli altri membri del gruppo sono vicini - Notifica di prossimità impostata + Avviso di prossimità impostato Ti notificheremo quando %1$s sarà a %2$s da te. Ti notificheremo quando qualcuno sarà a %1$s da te. - Notifica di prossimità annullata + Avviso di prossimità annullato Mostra come lista Mostra come griglia @@ -2523,12 +2551,12 @@ Scegli una copertina per il tuo video del profilo Imposta come principale Apri nell\'editor - Questa è ora la tua foto principale. - Questo è ora il tuo video principale. - Questa è ora la foto principale del canale. - Questo è ora il video principale del canale. - Questa è ora la foto principale del gruppo. - Questo è ora il video principale del gruppo. + Questa ora è la tua foto principale. + Questo ora è il tuo video principale. + Questa ora è la foto principale del canale. + Questo ora è il video principale del canale. + Questa ora è la foto principale del gruppo. + Questo ora è il video principale del gruppo. Foto salvata nella galleria Video salvato nella galleria Foto salvata nei download @@ -2574,6 +2602,7 @@ Ritorna alle Impostazioni Ritorna al Passport Imposta password + Show password Imposta password aggiuntiva Puoi impostare una password che sarà richiesta quando accedi su un nuovo dispositivo oltre al codice che ricevi via SMS. La tua password @@ -2597,9 +2626,9 @@ Ci siamo quasi! Controlla la tua email (non dimenticare lo spam) per completare la configurazione della verifica in due passaggi. Fatto! - La password per la verifica in due passaggi è ora attiva. + La password per la verifica in due passaggi ora è attiva. La tua password per la verifica in due passaggi è stata cambiata. - La tua email di recupero per la verifica in due passaggi è ora attiva. + La tua email di recupero per la verifica in due passaggi ora è attiva. La tua email di recupero per la verifica in due passaggi è stata cambiata. Cambia password Disattiva password @@ -2630,7 +2659,7 @@ Codice di recupero Abbiamo inviato un codice di ripristino all\'email che ci hai fornito:\n\n%1$s Per favore controlla la tua email e inserisci il codice a 6 cifre che ti abbiamo inviato lì. - Hai problemi ad accedere alla tua email %1$s? + Impossibile accedere a %1$s? Hai problemi ad accedere alla tua email? Se non puoi ripristinare l\'accesso alla tua email, non ti resta che ricordare la tua password o ripristinare il tuo account. RIPRISTINA IL MIO ACCOUNT @@ -2654,6 +2683,7 @@ Utilizzo disco e rete Utilizzo archivio Utilizzo dati + Percorso archiviazione Cellulare Wi-Fi Roaming @@ -2677,7 +2707,7 @@ Privacy Ultimo accesso e in linea Foto del profilo - Chi può vedere la mia foto del profilo? + Chi può vedere le foto e i video del mio profilo? Puoi decidere chi può vedere la tua foto del profilo con precisione granulare. Puoi aggiungere utenti o interi gruppi come eccezioni che annulleranno le impostazioni precedenti. Numero di telefono @@ -2734,7 +2764,7 @@ Chi può vedere il tuo ultimo accesso? Aggiungi eccezioni "Aggiungi alle eccezioni " - Non vedrai l\'ultimo accesso e lo stato in linea delle persone con cui non condividi l\'ultimo accesso. Verrà mostrato un orario approssimativo (di recente, entro una settimana, entro un mese). + Non vedrai l\'ultimo accesso o lo stato in linea delle persone con cui non condividi il tuo. Verrà mostrato un orario approssimativo (di recente, entro una settimana, entro un mese). Hai modificato alcune impostazioni della privacy. Applicare le modifiche? Condividi con Non condividere con @@ -2852,6 +2882,14 @@ un1 ora è a %1$s da te Ora sei a %1$s da un1 un1 ora è a %1$s da un2 + un1 ti ha invitato in questo gruppo + un1 ti ha invitato in questo canale + un1 ha iniziato una chat vocale + Hai iniziato una chat vocale + Chat vocale terminata (%s) + un1 ha invitato un2 nella chat vocale + Hai invitato un2 nella chat vocale + un1 ti ha invitato nella chat vocale Hai permesso a questo bot di scriverti quando ti sei collegato su %1$s. %1$s ha ricevuto i seguenti documenti: %2$s Dettagli personali @@ -2908,9 +2946,9 @@ Per favore accedi al tuo account Telegram per usare Telegram Passport. Questo numero è stato bloccato. Codice scaduto, per favore riprova l\'accesso. - Troppi tentativi, per favore riprova più tardi + Troppi tentativi, per favore riprova più tardi. Troppi tentativi, per favore riprova tra %1$s - Codice non valido + Codice non valido, per favore riprova. Spiacenti, hai eliminato e ricreato il tuo account troppe volte di recente. Per favore attendi alcuni giorni prima di iscriverti di nuovo. Nome non valido Spiacenti, questo cognome non può essere usato @@ -2946,7 +2984,7 @@ Sei sicuro di voler eliminare la chat con **%1$s**? Sei sicuro di voler eliminare la chat con **%1$s** e bloccarlo? Sei sicuro di voler eliminare i **Messaggi salvati**? - Sei sicuro di voler eliminare la chat segreta con **%1$s**? + Sei sicuro di voler eliminare la tua chat segreta con **%1$s**? Sei sicuro di voler eliminare la chat **%1$s**? Elimina le bozze cloud Sei sicuro di voler eliminare tutte le bozze? @@ -2991,8 +3029,8 @@ Vuoi inviare questo contatto a **%1$s**? Non esiste alcun account Telegram con questo username. Questo bot non può unirsi ai gruppi. - Vuoi attivare le anteprime estese per i link nelle Chat segrete? Ricorda che le anteprime dei link sono generate sui server di Telegram. - Per favore nota che i bot inline sono forniti da sviluppatori di terze parti. Per far funzionare il bot, i caratteri che digiti dopo l\'username del bot sono inviati al rispettivo sviluppatore. + Attivare le anteprime estese per i link nelle Chat segrete? Ricorda che le anteprime dei link sono generate sui server di Telegram. + Per favore nota che i bot inline sono forniti da sviluppatori di terze parti. Per far funzionare il bot, i caratteri che digiti dopo l\'username del bot sono inviati al suo sviluppatore. Spiacenti, non puoi modificare questo messaggio. Per favore consenti a Telegram di ricevere chiamate così potremo inserire in automatico il codice per te. Per favore permetti a Telegram di ricevere chiamate e leggere il registro delle chiamate in modo da poter inserire il codice per te automaticamente. @@ -3022,13 +3060,16 @@ Telegram deve accedere alla tua memoria per poter inviare e salvare foto, video, musica e altri media. Telegram deve accedere al microfono affinché tu possa inviare messaggi vocali. Telegram deve accedere al microfono affinché tu possa registrare video. - Telegram deve avere accesso alla fotocamera affinché tu possa scattare foto e registrare video. Per favore attivalo nelle Impostazioni. + Telegram deve accedere alla fotocamera affinché tu possa scattare foto e registrare video. Per favore attivalo nelle Impostazioni. Telegram deve accedere alla tua posizione affinché tu possa condividerla con i tuoi amici. Telegram deve accedere alla tua posizione. - Telegram deve accedere allo spostamento su altre app per riprodurre i video in modalità PiP. + Telegram deve accedere allo spostamento su altre app per riprodurre i video in modalità Picture-in-Picture. + La modalità overlay ti consente di utilizzare il push-to-talk e vedere chi sta parlando anche quando sei fuori da Telegram. IMPOSTAZIONI Per favore consenti a Telegram di essere visualizzato sulla schermata di blocco in modo che le chiamate possano funzionare correttamente. Per condividere la posizione in tempo reale in questa chat, Telegram ha bisogno di accedere alla tua posizione in qualsiasi momento, anche quando l\'applicazione è in background.\n\nAccederemo alla tua posizione solo per la durata da te scelta, e potrai smettere di condividerla in qualsiasi momento. Non useremo la tua posizione per nessun altro scopo se non quello di condividerla in questa chat. + Picture-in-Picture + Overlay chat vocale Crescita Follower @@ -3127,7 +3168,7 @@ Inizia a messaggiare Impostazioni account - Usa meno dati per chiamare + Meno dati per le chiamate Chiamata in entrata Connetto Scambio chiavi di crittografia @@ -3141,9 +3182,14 @@ Chiamata Telegram Videochiamata Telegram Chiamata Telegram in corso + Chat vocale in corso Termina Altra chiamata in corso - Al momento hai una chiamata in corso con **%1$s**. Vuoi riagganciare e iniziarne una nuova con **%2$s**? + Terminare la chiamata con **%1$s** e iniziarne una nuova con **%2$s**? + Terminare la chiamata con **%1$s** e iniziare una chat vocale in **%2$s**? + Un\'altra chat vocale in corso + Lasciare la chat vocale in **%1$s** e iniziarne una nuova in **%2$s**? + Lasciare la chat vocale in **%1$s** e chiamare **%2$s**? Chiamate Suoneria Puoi personalizzare la suoneria usata quando questo contatto ti chiama su Telegram. @@ -3159,8 +3205,10 @@ Solo in roaming Rispondi Rifiuta - Al momento non sei in linea. Per favore connettiti a Internet per chiamare. + Al momento non sei in linea. Connettiti a Internet per chiamare. + Al momento non sei in linea. Connettiti a Internet per partecipare alle chat vocali. Al momento hai la modalità aereo attivata. Per favore disattivala o connettiti ad una rete Wi-Fi per chiamare. + Al momento la modalità aereo è attiva. Disattivala o connettiti al Wi-Fi per partecipare alle chat vocali. Non in linea Modalità aereo Impostazioni @@ -3175,7 +3223,7 @@ Videochiamata annullata Videochiamata rifiutata %1$s (%2$s) - Non hai ancora effettuato alcuna chiamata. + Ancora nessuna chiamata... L\'app di **%1$s** sta usando un protocollo non compatibile. Deve aggiornare la sua app prima che tu possa chiamarlo. L\'app di **%1$s** non supporta le chiamate. Deve aggiornare la sua app prima che tu possa chiamarlo. Spiacenti, **%1$s** sta usando una vecchia versione di Telegram che non supporta le videochiamate. @@ -3226,6 +3274,11 @@ Il video era pixellato Tocca qui per attivare la tua videocamera Attiva + o tieni premuto e parla + Sei in diretta + Silenziato dall\'amministratore + Silenziato + Sei in modalità solo ascolto Muto Avvia video Ferma video @@ -3239,11 +3292,66 @@ Rifiuta Riprova Video - Sei sicuro di voler chiamare %1$s? + Sei sicuro di voler chiamare **%1$s**? Chiamata vocale Sei sicuro di voler videochiamare **%1$s**? Videochiamata Riconnetto + Avvia chat vocale + Chat vocale + Iniziare una chat vocale in questo gruppo? + Gestire le chat vocali + Unisciti + %1$s membri stanno parlando + %1$s membro sta parlando + %1$s membri stanno parlando + %1$s membri stanno parlando + %1$s membri stanno parlando + %1$s membri stanno parlando + sta parlando + sta ascoltando + invitato + Lascia + Termina + Silenzia microfono + Sei sicuro di voler silenziare **%1$s** in questa chat vocale? + Rimuovi membro + Vuoi rimuovere %1$s dalla chat di gruppo? + **%1$s** rimosso dal gruppo. + **%1$s** ora può parlare. + **%1$s** ora è silenziato in questa chat. + Silenzia + Nuovi partecipanti attivi + Nuovi partecipanti silenziati + Condividi link d\'invito + Termina chat vocale + Connetto... + Lasciare la chat vocale + Sei sicuro di voler lasciare questa chat vocale? + Termina chat vocale + Sei sicuro di voler terminare questa chat vocale? + Termina chat vocale + CHAT VOCALE + Chat vocale + Apri chat vocale + L\'utente selezionato è già in questa chat vocale. + Spiacenti, non puoi unirti alle chat vocali come amministratore anonimo. + un1 ha invitato un2 nella chat vocale + Unisciti alla chat vocale + Ehi! Unisciti alla nostra chat vocale: %1$s + Invita membri + Rimuovi + Permetti di parlare + Cerca membri da invitare... + Copia link d\'invito + Link d\'invito copiato negli appunti. + Tocca per riattivare + Chat vocale terminata. Iniziarne una nuova? + Aggiungi membro + Vuoi aggiungere **%1$s** a **%2$s**? + Hai invitato **%1$s** nella chat vocale. + Aggiungi + Tocca per unirti Invia un messaggio a %1$s Chiama %1$s @@ -3273,12 +3381,12 @@ %1$d contatti su Telegram %1$d contatti su Telegram %1$d contatti su Telegram - Ehi, sto usando Telegram per messaggiare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s - Ehi, sto usando Telegram per messaggiare – così come %1$d altro nostri contatti. Unisciti a noi! Scaricalo qui: %2$s - Ehi, sto usando Telegram per messaggiare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s - Ehi, sto usando Telegram per messaggiare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s - Ehi, sto usando Telegram per messaggiare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s - Ehi, sto usando Telegram per messaggiare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s + Ehi, sto usando Telegram per chattare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s + Ehi, sto usando Telegram per chattare – così come %1$d altro nostri contatti. Unisciti a noi! Scaricalo qui: %2$s + Ehi, sto usando Telegram per chattare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s + Ehi, sto usando Telegram per chattare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s + Ehi, sto usando Telegram per chattare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s + Ehi, sto usando Telegram per chattare – così come altri %1$d dei nostri contatti. Unisciti a noi! Scaricalo qui: %2$s %1$d chat %1$d chat %1$d chat @@ -3327,6 +3435,12 @@ %1$d membri %1$d membri %1$d membri + %1$d partecipanti + %1$d partecipante + %1$d partecipanti + %1$d partecipanti + %1$d partecipanti + %1$d partecipanti e altri %1$d stanno scrivendo e %1$d altro stanno scrivendo e altri %1$d stanno scrivendo @@ -3346,7 +3460,7 @@ %1$d nuovi messaggi %1$d nuovi messaggi %1$d messaggi tolti - messaggio tolto + Messaggio tolto %1$d messaggi tolti %1$d messaggi tolti %1$d messaggi tolti @@ -3750,7 +3864,10 @@ Ricevuto %s Programmato per le %s Torna indietro - Apri menù di navigazione + Apri menu di navigazione + Apri menu + Chiudi menu + Open in photo viewer %2$s di %1$s Altre opzioni Play @@ -3898,4 +4015,5 @@ \'Ricorda oggi alle\' HH:mm \'Ricorda il\' d MMM \'alle\' HH:mm \'Ricorda il\' d MMM yyyy \'alle\' HH:mm + Attiva diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index 4cecefcc5ed..6eb9521b4c0 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -37,7 +37,7 @@ 코드를 받지 못하셨나요? 코드를 SMS로 보내기 계정 초기화 취소 - Somebody with access to **%1$s** has requested to delete your Telegram account and reset your 2-Step Verification password.\n\nIf this wasn\'t you, please enter the code we\'ve just sent you via SMS. You can also cancel this by *changing your phone number*. + **%1$s**에 접근이 가능한 누군가가 회원님의 텔레그램 계정삭제 및 2단계 인증 초기화를 요청했습니다.\n\n만약 이것을 요청 하신게 아니라면, 저희가 방금 보낸 SMS 코드를 입력해주세요. 또한 *전화번호를 변경을 하여* 취소를 할 수 있습니다. 계정 초기화 계정 **%1$s**이 비밀번호로 보호되어 있기에, 보안 목적으로 1주일 뒤에 이 계정을 삭제할 것입니다.\n\n이 작업은 언제든지 취소하실 수 있습니다. 아래 시간이 지나야 계정을 초기화하실 수 있습니다: @@ -45,7 +45,7 @@ 초기화 링크가 폐기되거나 만료되었습니다. %1$s 계정 탈퇴 작업이 취소되었습니다. 이제 이 창을 닫으셔도 좋습니다. - Your login code is **%1$s**. Enter it in the Telegram app where you are trying to log in.\n\nDo not give this code to anyone. + 로그인 코드는 **%1$s**입니다. 로그인하고자 하는 텔레그램 앱에 입력하세요.\n\n아무에게도 이 코드를 주지 마세요. 성명 이름을 입력하고 프로필 사진을 추가하세요. @@ -165,6 +165,7 @@ 고정 고정 해제 보관 + 보관함 보관 해제 보관한 대화방 대화방 삭제 @@ -172,7 +173,7 @@ 대화방 선택 대화방 선택 비밀 사진 - 비밀 동영상 + 사라지는 동영상 비밀 GIF %1$s님의 텔레그램 버전이 낮아 비밀 사진을 호환성 모드로 표시합니다.\n\n%2$s님이 텔레그램을 업데이트하고 나면, 자동삭제 시간이 1분 이하인 사진은 \"탭하고 누르고 있어야 보임\" 상태가 되며, 상대방이 화면을 캡처할 때 마다 알림을 받습니다. 메시지 @@ -181,7 +182,7 @@ %1$s 동안 끄기 알림 끄기 %1$s 뒤 - 영원히 음소거 + 사용 안 함 해시태그 최근 사람들 @@ -227,30 +228,30 @@ 연락처 목록에 없는 사용자에게서 새로운 메시지를 많이 받고 계십니다. 해당 대화방에 **자동 알림 끄기**와 **보관**을 적용하시겠습니까? 설정으로 이동 프로필 열기 - Open Channel + 채널 열기 Open Group 메시지 보내기 언급 - Notifications muted - Notifications muted for %1$s - Notifications unmuted + 알림 음소거 됨 + %1$s동안 알림 음소거 + 알림 활성화 됨 메시지 %1$d 개가 삭제가 되었습니다. 메시지 %1$d 개가 삭제가 되었습니다. 메시지 %1$d 개가 삭제가 되었습니다. 메시지 %1$d 개가 삭제가 되었습니다. 메시지 %1$d 개가 삭제가 되었습니다. 메시지 %1$d 개가 삭제가 되었습니다. - No Results + 결과 없음 결과 없음 검색을 다시 해보세요. - Music from all your chats will be shown here. - Files from all your chats will be shown here. - Links from all your chats will be shown here. - Voice from all your chats will be shown here. - Media from all your chats will be shown here. + 모든 대화에서의 음악이 여기에 표시가 됩니다 + 모든 대화에서의 파일이 여기에 표시가 됩니다 + 회원님의 모든 대화방에 있는 링크가 여기에 보입니다. + 모든 대화에서의 음성메시지가 여기에 표시가 됩니다 + 회원님의 모든 대화방에 있는 미디어가 여기에 보입니다. 대화방 - Message pinned - Message unpinned + 메시지가 고정되었습니다 + 메시지 고정이 해제되었습니다 관리자로 승격 관리자 권한 수정 @@ -389,7 +390,7 @@ 채널을 관리하는 데 도움을 줄 만한 관리자를 추가하실 수 있습니다. 관리자를 제명하려면 길게 누르세요. \'%1$s\' 채널에 들어가시겠습니까? 죄송합니다. 이 대화방에는 더 이상 접근하실 수 없습니다. - Sorry, you can\'t access this chat because you were banned by an admin. + 죄송합니다. 관리자에게 차단되었기에 이 대화방에 접근하실 수 없습니다. 안타깝지만, 공개 그룹에 참가하시는 것이 금지되었습니다. 죄송합니다. 이 대화방에는 더 이상 접근하실 수 없습니다. %1$s 님을 채널에 추가할까요? @@ -444,14 +445,14 @@ 다른 사람의 메시지 삭제 메시지 삭제 새로운 관리자 추가 - 익명으로 보내기 + 익명으로 남기 관리자 권한 회수 그룹 소유권 넘기기 채널 소유권 넘기기 보안 확인 사항 아래 경우에만 이 그룹을 **%1$s** 님에게 넘기실 수 있습니다: 다음 경우에만 이 채널을 **%1$s** 님에게 넘기실 수 있습니다: - **7일** 전에 **2단계 인증**을 켬 + 지난 **7일**이상동안 **2단계 인증**을 활성화 함. **24시간** 전에 이 기기에 로그인함 나중에 다시 시도하세요. 비밀번호 설정 @@ -538,10 +539,10 @@ 토론 보기 논평을 나눌 그룹 대화방을 추가하세요. 연결된 채널 - Select a group chat that will host comments from your channel. + 채널에서의 코멘트들을 호스트할 그룹 대화를 선택해주세요. 채널에 게시하시는 모든 것이 이 그룹으로 전달됩니다. - **%1$s** is selected as the group that hosts comments for your channel. - **%1$s** 채널이 그룹을 토론 게시판으로 삼아 잇고 있습니다. + %1$s 대화방이 채널을 위한 코멘트 주최 그룹으로 선택되었습니다. + 이 그룹은 %1$s의 토론 게시판으로 연결 되어 있습니다. 이 채널에 새로 게시되는 메시지가 모두 그룹으로 전달됩니다. 새로운 그룹 만들기 그룹 끊어내기 @@ -566,7 +567,8 @@ 저속 모드가 켜져 있습니다. 한 번에 메시지를 하나 이상 보내실 수 없습니다. 저속 모드가 켜져 있습니다. 항목을 더 선택하실 수 없습니다. 죄송합니다. 이 글은 한 메시지로 치기에 너무 깁니다.\n\n저속 모드가 켜져 있습니다. 한 번에 메시지를 하나 이상 보내실 수 없습니다. - **%1$s** promoted to admin + %1$s님이 관리자로 승격됨 + **%1$s** removed from **%2$s** 새로운 설문 새로운 퀴즈 @@ -671,7 +673,7 @@ 원본 설명 없음 un1 님이 아래 메시지를 고정했습니다: - un1 님이 메시지를 고정했습니다. + un1님이 메시지 고정을 해제했습니다 un1 님이 설문을 마감했습니다: un1 님이 퀴즈를 마감했습니다: un1 님이 아래 메시지를 삭제했습니다: @@ -716,8 +718,9 @@ 메시지 수정 메시지 삭제 관리자 추가 - 익명으로 보내기 + 익명으로 유지 사용자 차단 + 음성 대화 관리 사용자 추가 제목: %1$s 제목 @@ -732,8 +735,15 @@ 메시지 수정 메시지 고정 나간 참가자 + 음성 대화 un1 님이 저속 모드 타이머를 %1$s(으)로 맞췄습니다 un1 님이 저속 모드를 껐습니다 + un1님이 음성 대화를 시작했습니다 + un1님이 음성 대화를 종료했습니다 + 음성 대화에서 un1님이 un2님을 음소거 했습니다 + 음성 대화에서 un1님이 un2님의 음소거를 해제했습니다 + un1님이 새 참가자들에 대한 음소거를 해제했습니다 + un1님이 새 참가자들을 음소거 했습니다 새 단체 메시지 리스트 리스트 이름을 입력하세요 @@ -886,7 +896,7 @@ %1$s 님을 연락처에 추가하기 연락처 보기 텔레그램 메시지와 전화 수신에서 **%1$s** 님을 차단하시겠습니까? - Do you want to block messages from **%1$s**? + **%1$s**님의 메시지를 차단하겠습니까? 정말 이 사용자가 보낸 스팸을 신고하시겠습니까? 정말 이 그룹의 스팸 메시지를 신고하시겠습니까? 정말 이 채널에 게시된 스팸 메시지를 신고하시겠습니까? @@ -899,12 +909,12 @@ 저장한 GIF 파일을 보려면 탭하세요. 고정 모든 참가자에게 알리기 - Also pin for %1$s + %1$s에도 메시지 고정 고정 해제 메시지 고정 메시지 고정 해제 - Do you want to pin an older message while leaving a more recent one pinned? - 그룹에 있는 모든 참가자들에게 이 메시지를 고정하시겠습니까? + 최근 메시지의 고정을 유지하면서, 기존 메시지를 고정하시겠습니까? + 그룹에 메시지를 고정하겠습니까? 채널에 이 메시지를 고정하시겠습니까? 이 메시지를 대화방 위쪽에 고정하시겠습니까? 메시지를 고정 해제하시겠습니까? @@ -929,12 +939,19 @@ 기타 안내 고정된 메시지 - Previous Message + 이전 메시지 고정된 설문 수정됨 메시지 수정 설명 수정 미디어를 수정하려면 누르세요 + 사진 편집하기 + 비디오 편집하기 + 사진 교체하기 + 비디오 교체하기 + 미디어 교체하기 + 파일 교체하기 + 오디오 파일 교체하기 봇을 보려면 끌어 올리세요 %1$s 죄송합니다. 수정 시간이 만료되었습니다. @@ -1003,6 +1020,8 @@ 사진은 짧게, 동영상은 길게 누르세요 목록으로 보려면 누르세요. 소리 없이 보내기 + Send as a new photo + 사진 교체 지금 보내기 시간 조정하기 오늘 @@ -1039,37 +1058,37 @@ 대화방 가리기 정말 이 대화방을 가리시겠습니까? 가리기 - Send a message or tap on the greeting below to show that you are ready to chat. - %1$s is %2$s - %1$s is %2$s + 메시지를 보내거나 아래의 인삿말을 눌러 회원님이 대화할 준비가 되었음을 보여 주세요. + %1$s 님이 %2$s 밖에 있음 + %1$s님이 %2$s에 있음 대화방을 메인 목록으로 옮겼습니다. d s m h w - to private messages and groups + 개인 메시지 및 그룹 Transfer Bot Ownership This will transfer the **full owner** rights for the bot to the selected user. Change Owner - You can transfer bot only if you have: - 코멘트 남기기 + You can transfer this bot only if you have: + 댓글 남기기 코멘트 코멘트 보내기 답변 - 아직 코멘트가 없습니다... + 코멘트가 없습니다... No replies here yet... 대화에서 보기 익명으로 보내기 토론이 시작되었습니다 - 쓰레드 보기 - Choose date - This chat helps you keep track of replies to your comments in Channels. - Sorry, this post has been removed from the discussion group. - UNPIN ALL MESSAGES - HIDE PINNED MESSAGES - Pinned messages hidden - Pinned messages will be shown again if a new message is pinned. + 스레드 보기 + 날자 선택 + 이 대화방에서 채널 속 회원님의 코멘트에 남겨진 답변들을 모아 보실 수 있습니다. + 죄송합니다. 이 게시물은 토론 그룹에서 제거되었습니다. + 모든 메시지 고정해제 + 고정된 메시지 숨기기 + 고정된 메시지 숨김 + 새로운 메시지가 고정되었을 때 고정된 메시지가 다시 보입니다. %1$s 님이 자동 삭제 타이머를 %2$s(으)로 맞췄습니다 자동 삭제 타이머를 %1$s(으)로 맞추셨습니다 @@ -1126,6 +1145,10 @@ %1$s 님이 %2$s 그룹 사진을 바꿨습니다 %1$s changed the group video for %2$s %1$s 님이 %3$s 님을 %2$s 그룹에 초대했습니다 + %1$s invited %3$s to a voice chat in %2$s + %1$s 님이 나를 %2$s의 음성 대화에 초대했습니다 + %1$s started a voice chat in %2$s + %2$s 그룹에서 %1$s님이 음성 대화를 종료했습니다 %1$s 님이 %2$s 그룹에 돌아왔습니다 %1$s 님이 %2$s 그룹에 들어왔습니다 %1$s 님이 %3$s 님을 %2$s 그룹에서 추방했습니다 @@ -1158,7 +1181,7 @@ %1$s 님이 %2$s 그룹에 파일을 고정했습니다 %1$s 님이 %2$s 그룹에 스티커를 고정했습니다 %1$s 님이 %2$s 그룹에 %3$s 스티커를 고정했습니다 - %1$s 님이 %2$s 그룹에 음성 메시지를 고정했습니다 + %1$s님이 %2$s에 음성 메시지를 고정했습니다 %1$s 님이 %2$s 그룹에 동영상 메시지를 고정했습니다 %1$s 님이 %3$s 연락처를 %2$s 그룹에 고정했습니다 %1$s 님이 %2$s 그룹에 지도를 고정했습니다 @@ -1185,25 +1208,25 @@ %1$s 님이 실시간 위치를 고정했습니다 %1$s 님이 GIF를 고정했습니다 %1$s 님이 오디오 파일을 고정했습니다 - %1$s pinned \"%2$s\" + %1$s님이 %2$s을(를) 고정했습니다 %1$s pinned a message - %1$s pinned a poll %2$s - %1$s pinned a quiz %2$s - %1$s pinned a photo - %1$s pinned a game + %1$s님이 설문 %2$s을(를) 고정했습니다 + %1$s님이 퀴즈 %2$s를 고정했습니다 + %1$s님이 사진을 고정했습니다 + %1$s님이 게임을 고정했습니다 %1$s pinned a game score - %1$s pinned a video - %1$s pinned a file + %1$s님이 동영상을 고정했습니다 + %1$s님이 파일을 고정했습니다 %1$s pinned an invoice - %1$s pinned a sticker + %1$s님이 스티커를 고정했습니다 %1$s pinned a %2$s sticker - %1$s pinned a voice message - %1$s pinned a video message - %1$s pinned a contact %2$s - %1$s pinned a map - %1$s pinned a live location - %1$s pinned a GIF - %1$s pinned an audio file + %1$s님이 음성 메시지를 고정했습니다 + %1$s님이 동영상 메시지를 고정했습니다 + %1$s님이 연락처 %2$s님을 고정했습니다 + %1$s님이 지도를 고정했습니다 + %1$s님이 실시간 위치를 고정했습니다 + %1$s님이 GIF를 고정했습니다 + %1$s님이 오디오 파일을 고정했습니다 텔레그램 연락처 선택 @@ -1240,12 +1263,12 @@ 마지막 접속순으로 정렬 %1$s 추가 전화번호 - You have no contacts on Telegram yet - Invite friends to try Telegram - Find people nearby to chat with - Search people by username + 아직 텔레그램에 연락처가 없습니다 + 친구를 텔레그램으로 초대해보세요 + 주위에 대화할 사람들을 찾아보세요 + 아이디를 통해 사람들을 찾아보세요 New contact - The phone number **%1$s** is not in your contact list. Do you want to add it? + The phone number **%1$s** is not in your contacts. Do you want to add it? Add contact 사람들을 추가하세요... @@ -1262,6 +1285,7 @@ 들어가기 링크를 클립보드에 복사했습니다 링크가 클립보드에 복사되었습니다.\n이 링크는 이 대화방의 참가자에게만 작동합니다. + This link will only work for members of this chat. 안타깝게도 이 메시지에 접근하실 수 없습니다. 회원님은 메시지가 게시된 대화방의 참가자가 아닙니다. 전화번호를 클립보드에 복사했습니다 이메일을 클립보드에 복사했습니다 @@ -1284,7 +1308,7 @@ 설정 구독자 추가 참가자 추가 - 관리자 설정 + 관리자 추가 그룹에서 차단 그룹 삭제하고 나가기 그룹 삭제 및 나가기 @@ -1296,7 +1320,7 @@ 슈퍼그룹으로 변환 경고 이 작업은 되돌릴 수 없습니다. 슈퍼그룹에서 일반 그룹으로는 내리실 수 없습니다. - **참가자 수 한계에 다다랐습니다.**\n\n더 많은 참가자를 추가하고 추가 기능을 사용하려면, 슈퍼그룹으로 업그레이드하세요.\n\n• 슈퍼그룹은 %1$s명까지 수용할 수 있습니다\n• 새로운 참가자가 대화 기록 전체를 볼 수 있습니다\n• 한 사람이 메시지를 삭제하면 모두에게서 사라집니다\n• 생성자가 그룹에 공개 링크를 둘 수 있습니다 + **참가자 수 한계에 다다랐습니다.**\n\n더 많은 참가자를 추가하고 추가 기능을 사용하려면, 슈퍼그룹으로 업그레이드하세요.\n\n• 슈퍼그룹은 %1$s명까지 수용할 수 있습니다\n• 새로운 참가자가 대화 기록 전체를 볼 수 있습니다\n• 메시지 삭제시 모두에게 삭제됩니다\n• 관리자는 그룹에 설명을 추가 할 수 있습니다\n• 생성자가 그룹에 공개 링크를 설정 할 수 있습니다 **슈퍼그룹에서는**\n\n• 새로운 참가자가 대화 내용 전체를 볼 수 있습니다\n• 한 사람이 메시지를 삭제하면 모두에게서도 사라집니다\n• 생성자가 그룹에 공개 링크를 둘 수 있습니다 **주의:** 이 작업은 되돌릴 수 없습니다. @@ -1307,7 +1331,7 @@ %1$s 님은 아직 텔레그램에 가입하지 않았습니다. 초대하시겠습니까? 초대 BLOCK - BLOCK AND DELETE REPLIES + 차단 및 답글 삭제 사용자 차단 사용자 차단 사용자 차단 @@ -1366,7 +1390,7 @@ 올바른 사용자명을 입력하세요. 사용자명은 5자 이상이어야 합니다. 사용자명은 32자를 넘길 수 없습니다. - 죄송합니다. 사용자명은 숫자로 시작할 수 없습니다. + 사용자명은 숫자로 시작할 수 없습니다. **텔레그램** 사용자명을 정하실 수 있습니다. 회원님의 전화번호를 모르는 사람도 이 사용자명으로 회원님을 찾아 연락할 수 있습니다.\n\n**a부터 z 사이 글자**, **0부터 9 사이 숫자**와 밑줄을 사용하실 수 있습니다. 최소 길이는 **다섯** 자입니다. 아래 링크로 회원님과의 대화방이 열립니다:\n%1$s 사용자명을 확인하고 있습니다... @@ -1814,6 +1838,10 @@ 대화 중 소리 기본 기본값 + 기본값 + 앱내 기본값 + %1$s In-App + 음소거 스마트 알림 예외 예외 추가 @@ -1960,7 +1988,7 @@ 계산 중... 문서 사진 - 음성/동영상 메시지 + 음성 및 영상 메시지 동영상 음악 GIF @@ -2316,8 +2344,8 @@ 공유한 미디어 그룹 링크 - 오디오 - 음성 메시지 + 음악 + 음성 GIF 공유한 파일 공유하는 콘텐츠 @@ -2381,8 +2409,8 @@ 방금 업데이트됨 나와 %1$s 님 %1$s를 %2$s와 공유 중 - %1$s sharing with %2$s - %1$s sharing with %2$s + %2$s에서 %1$s 공유 중 + %2$s에서 %1$s를 공유 중 모두 중단 실시간 위치를 %1$s와 공유하고 있습니다 %1$s 님에게 회원님의 정확한 위치를 얼마 동안 보일지 선택하세요. @@ -2411,19 +2439,19 @@ 이 위치로 설정하기 사람들이 회원님의 그룹을 \"주변 사람\" 섹션에서 찾을 수 있습니다. 지역에 있는 장소 - Proximity alert - Notify when %1$s is within %2$s - Notify when someone is within %1$s - You are already closer than %1$s - Share Location - Share - For the alert to work, please share your live location in this chat. - Alert when %1$s is close - Alert when other members of the group are close - Proximity alert set - We will notify you once %1$s is within %2$s from you. - We will notify you once someone is within %1$s from you. - Proximity alert cancelled + 근접 경고 + %1$s님이 %2$s내 있을때 알림 + %1$s내에 누가 근접시 알림 + 이미 %1$s 보다 더 가까이 있습니다. + 위치 공유 + 공유 + 알림을 작동시키려면, 이 대화방에 회원님의 실시간 위치를 공유해주세요. + %1$s님이 가까워졌을때 알림 + 그룹 내 다른 사용자가 근접 했을때 알리기 + 근접 알림 설정됨 + %1$s님이 %2$s내 접근시 알림을 드리겠습니다 + 누군가가 %1$s내에 접근시 알림을 드리겠습니다 + 근접 알림 취소됨 목록으로 보기 그리드로 보기 @@ -2485,9 +2513,9 @@ 이 동영상을 정말 삭제하시겠습니까? GIF 삭제 정말 이 GIF를 삭제하시겠습니까? - Are you sure you want to delete this photo for everyone? + 모두에게 이 사진을 삭제하겠습니까? Are you sure you want to delete this video for everyone? - Are you sure you want to delete this GIF for everyone? + 모두에게 이 GIF를 삭제하겠습니까? 변경 사항을 삭제할까요? Are you sure you want to discard all changes? 검색 기록을 비울까요? @@ -2505,10 +2533,10 @@ 설명 삭제 수정 - Pen - Marker - Neon - Arrow + + 마커 + 네온 + 화살표 복제 외곽선 일반 @@ -2520,52 +2548,52 @@ 미디어를 하나의 메시지로 묶기 묶지 않고 보내기 압축 없이 보내기 - Choose a cover for your profile video + 프로필 동영상의 커버를 정하세요 메인으로 설정하기 Open in editor 앞으로 이것이 회원님의 메인 프로필 사진입니다. 앞으로 이것이 회원님의 메인 프로필 동영상입니다. - This is the main channel photo now. - This is the main channel video now. + 채널에 대표로 설정된 사진입니다. + 채널에 대표로 설정된 비디오입니다. 현재 그룹 대표 사진입니다. 현재 그룹 대표 영상입니다. - Photo saved to gallery - Video saved to gallery - Photo saved to downloads - Video saved to downloads - GIF saved to downloads - File saved to music - File saved to downloads - %1$d files saved to downloads - File saved to downloads - %1$d files saved to downloads - %1$d files saved to downloads - %1$d files saved to downloads - %1$d files saved to downloads - %1$d photos saved to gallery - Photo saved to gallery - %1$d photos saved to gallery - %1$d photos saved to gallery - %1$d photos saved to gallery - %1$d photos saved to gallery - %1$d videos saved to gallery - Video saved to gallery - %1$d videos saved to gallery - %1$d videos saved to gallery - %1$d videos saved to gallery - %1$d videos saved to gallery - %1$d files saved to music - File saved to music - %1$d files saved to music - %1$d files saved to music - %1$d files saved to music - %1$d files saved to music - %1$d items saved to gallery - One item saved to gallery - %1$d items saved to gallery - %1$d items saved to gallery - %1$d items saved to gallery - %1$d items saved to gallery + 갤러리로 사진이 저장됬습니다 + 갤러리로 영상이 저장됬습니다 + 다운로드로 사진이 저장됬습니다 + 다운로드로 동영상이 저장됬습니다 + 다운로드로 GIF가 저장됬습니다 + 음악에 파일이 저장됬습니다 + 다운로드로 파일이 저장됬습니다 + 다운로드에 %1$d개의 파일이 저장됬습니다 + 다운로드에 %1$d개의 파일이 저장됬습니다 + 다운로드에 %1$d개의 파일이 저장됬습니다 + 다운로드에 %1$d개의 파일이 저장됬습니다 + 다운로드에 %1$d개의 파일이 저장됬습니다 + 다운로드에 %1$d개의 파일이 저장됬습니다 + 갤러리에 %1$d개의 사진이 저장됬습니다 + 갤러리에 %1$d개의 사진이 저장됬습니다 + 갤러리에 %1$d개의 사진이 저장됬습니다 + 갤러리에 %1$d개의 사진이 저장됬습니다 + 갤러리에 %1$d개의 사진이 저장됬습니다 + 갤러리에 %1$d개의 사진이 저장됬습니다 + 갤러리로 %1$d개의 비디오가 저장됬습니다 + 갤러리로 %1$d개의 비디오가 저장됬습니다 + 갤러리로 %1$d개의 비디오가 저장됬습니다 + 갤러리로 %1$d개의 비디오가 저장됬습니다 + 갤러리로 %1$d개의 비디오가 저장됬습니다 + 갤러리로 %1$d개의 비디오가 저장됬습니다 + 음악에 %1$d개 파일이 저장됬습니다 + 음악에 %1$d개 파일이 저장됬습니다 + 음악에 %1$d개 파일이 저장됬습니다 + 음악에 %1$d개 파일이 저장됬습니다 + 음악에 %1$d개 파일이 저장됬습니다 + 음악에 %1$d개 파일이 저장됬습니다 + 갤러리로 %1$d개의 아이템이 저장됬습니다 + 갤러리로 %1$d개의 아이템이 저장됬습니다 + 갤러리로 %1$d개의 아이템이 저장됬습니다 + 갤러리로 %1$d개의 아이템이 저장됬습니다 + 갤러리로 %1$d개의 아이템이 저장됬습니다 + 갤러리로 %1$d개의 아이템이 저장됬습니다 2단계 인증 2단계 인증 @@ -2574,6 +2602,7 @@ Return to Settings Return to Passport Set Password + Show password 추가 비밀번호 설정 새로운 기기에 로그인할 때 SMS로 받는 코드와 별개로 입력해야 하는 비밀번호를 설정하실 수 있습니다. 비밀번호 @@ -2630,7 +2659,7 @@ 복구 코드 제공하신 이메일로 복구 코드를 보냈습니다:\n\n%1$s 이메일을 확인하여 보내 드린 6자리 코드를 입력해 주세요. - %1$s 이메일에 접근하는 데 문제가 있으신가요? + %1$s 접근에 어려움이 있으신가요? Having trouble accessing your email? 이메일에 접근하지 못한다면, 비밀번호를 기억해 내거나 계정을 초기화하시는 수밖에 없습니다. 계정 초기화 @@ -2654,6 +2683,7 @@ 디스크 및 네트워크 사용량 저장 공간 사용량 데이터 사용량 + 저장 경로 모바일 Wi-Fi 로밍 @@ -2663,7 +2693,7 @@ 보낸 바이트 받은 바이트 파일 - 전화 설정 + 통화 발신 전화 수신 전화 전체 시간 @@ -2677,7 +2707,7 @@ 개인 정보 마지막 접속 및 온라인 프로필 사진 - 내 프로필 사진을 볼 수 있는 사람 + 누가 내 프로필 사진과 영상을 볼 수 있나요? 회원님의 프로필 사진을 볼 수 있는 사람을 세세하게 제한하실 수 있습니다. 사용자나 그룹 전체를 예외로 추가하여 앞선 설정을 무시하실 수 있습니다. 전화번호 @@ -2724,12 +2754,12 @@ 없음 (+%1$d) 보안 계정 자동 탈퇴 - New chats from unknown users - Archive and Mute - Automatically archive and mute new chats, groups and channels from non-contacts. - Delete my account + 알 수 없는 사용자가 만든 새로운 대화방 + 보관하고 알림 끄기 + 연락처에 등록되지 않은 사람들이 만든 새로운 대화방과 그룹, 채널들을 자동으로 보관하고 알림을 끕니다. + 계정 삭제하기 다음 기간 내 미접속 시 계정 탈퇴 - If away for + 다음 기간동안 비활성화 시 이 기간 안에 한 번이라도 접속하지 않으시면, 모든 그룹, 메시지, 연락처와 더불어 회원님의 계정이 사라집니다. 내 마지막 접속 시간을 볼 수 있는 사람 예외 추가 @@ -2754,7 +2784,7 @@ 죄송합니다. 사용자의 개인 정보 설정으로 인해 이 사용자를 그룹에 추가하실 수 없습니다. 죄송합니다. 사용자의 개인 정보 설정으로 인해 이 사용자를 채널에 추가하실 수 없습니다. 죄송합니다. 이 사용자의 개인 정보 설정으로 인해 함께 그룹을 만드실 수 없습니다. - 단대단을 끄시면, 회원님의 IP 주소를 노출시키지 않도록 모든 전화가 텔레그램 서버를 통해 전달됩니다. 다만 음성 품질이 약간 저하될 수 있습니다. + 단대단을 끄시면, 회원님의 IP 주소를 노출시키지 않도록 모든 통화가 텔레그램 서버를 통해 전달됩니다. 다만 음성 및 영상 품질이 저하될 수 있습니다. 동기화된 연락처 삭제 자주 이용하는 연락처 추천 신속한 연락을 위해 검색 구역 위쪽에 자주 대화하는 사람을 표시합니다. @@ -2849,9 +2879,17 @@ un1 님이 그룹에 돌아왔습니다 un1 님이 그룹에 들어왔습니다 그룹에 돌아오셨습니다 - un1 is now within %1$s from you - You are now within %1$s from un1 - un1 is now within %1$s from un2 + un1님이 회원님으로 부터 %1$s내 있습니다 + 회원님이 un1님으로부터 %1$s내 있습니다. + un1 님이 현재 un2 님으로부터 %1$s 안에 있습니다 + un1님이 그룹에 초대했습니다 + un1님이 채널에 초대했습니다 + un1님이 음성 대화를 시작했습니다 + 음성 대화를 시작했습니다 + 음성 대화 종료됨 (%s) + un1님이 un2님을 음성 대화에 초대했습니다 + un2 님을 음성 대화에 초대하셨습니다 + un1님이 음성 대화에 초대했습니다 %1$s에 로그인할 때 이 봇이 회원님에게 메시지를 보내도록 허용하셨습니다. %1$s 님이 다음 서류를 받았습니다: %2$s 개인 신상 명세 @@ -2910,7 +2948,7 @@ 코드가 만료되었습니다. 다시 로그인하세요. 너무 많이 시도하셨습니다. 나중에 다시 시도하세요. 너무 많이 시도하셨습니다. %1$s초 뒤에 다시 시도하세요. - 올바른 코드를 입력해 주세요 + 올바르지 않은 코드입니다. 다시 시도해주세요. 죄송합니다. 최근 들어 계정을 너무 많이 삭제한 뒤 재생성하셨습니다. 며칠 기다렸다 다시 가입해 주세요. 올바른 이름을 입력해 주세요 죄송합니다. 본 성을 사용하실 수 없습니다 @@ -3026,9 +3064,12 @@ 회원님의 위치를 친구들과 공유하려면 텔레그램에게 위치 접근 권한이 필요합니다. 텔레그램에게 위치 접근 권한이 필요합니다. 화면속화면 모드로 동영상을 재생하려면 텔레그램에게 다른 앱 위에 그릴 수 있는 권한을 부여하셔야 합니다. + 오버레이 모드는 푸시-투-토크시, 텔레그램을 나가더라도 누가 대화를 하는지 알 수 있게 됩니다. 설정 통화가 제대로 실행되도록 텔레그램이 잠금 화면에 나타나는 것을 허용해 주세요. To share your live location in this chat, Telegram needs access to your location all the time, including while the app is in the background.\n\nWe will access your location only for the duration you choose, and you can stop sharing it any time. We won\'t use your location for any purpose other than sharing it in this chat. + 화면-속-화면 + 음성 대화 오버레이 성장 팔로워 @@ -3102,14 +3143,14 @@ Top days of week 메시지 보기 프로필 열기 - Today - Yesterday + 오늘 + 어제 Views - Public Shares - Private Shares + 공개 공유 + 비공개 공유 View Stats View Channel Stats - Message Statistics + 메시지 통계 Open Message 텔레그램 @@ -3141,10 +3182,15 @@ 텔레그램 전화 텔레그램 영상 통화 텔레그램으로 통화 중 + 참여중인 음성 대화 통화 종료 이미 통화하고 계십니다 - 현재 **%1$s** 님과 통화하고 계십니다. 전화를 끊고 **%2$s** 님과 새로 통화하시겠습니까? - 음성 전화 + **%1$s**님과 통화를 종료하고 **%2$s**님과 새로 통화하겠습니까? + **%1$s**님과 전화를 종료하고 **%2$s**의 음성 대화를 시작하시겠습니까? + 다른 음성 대화가 진행중입니다 + **%1$s**의 음성 대화를 나가고, **%2$s**에서 새로운 음성 대화를 시작하겠습니까? + **%1$s**의 음성 대화를 나가고 **%2$s**에게 전화를 거시겠습니까? + 전화 벨소리 이 연락처에서 전화가 걸려올 때 울리는 벨소리를 맞춤하실 수 있습니다. 전화 @@ -3160,7 +3206,9 @@ 받기 거부 회원님은 현재 오프라인이십니다. 전화를 걸려면 인터넷에 연결해 주세요. + 현재 오프라인입니다. 음성 대화에 참여하려면 인터넷에 연결 해주세요. 비행기 모드가 현재 켜져 있습니다. 전화를 걸려면 비행기 모드를 끄거나 Wi-Fi에 연결하세요. + 현재 비행기 모드입니다. 음성 대화에 참여하려면, 비행기 모드를 종료하거나 와이파이에 연결 해주세요. 오프라인 비행기 모드 설정 @@ -3178,11 +3226,11 @@ 전화를 걸거나 받으신 적이 없습니다. **%1$s** 님의 앱은 호환되지 않는 프로토콜을 사용하고 있습니다. 상대가 앱을 업데이트한 뒤에서야 전화하실 수 있습니다. **%1$s** 님의 텔레그램은 전화를 지원하지 않습니다. 이 사용자의 앱을 업데이트한 뒤에 전화할 수 있습니다. - Sorry, **%1$s** is using an old version of Telegram that doesn\'t support video calls. - Make a voice call + %1$s 님의 앱이 영상 통화를 지원하지 않습니다. 전화를 거시기 전에 이 사용자가 앱을 업데이트해야 합니다. + 음성 통화 걸기 텔레그램 전화의 품질을 평가해주세요. 전화를 걸려면 텔레그램에게 마이크 접근 권한을 부여하셔야 합니다. - Telegram needs access to your microphone and camera so that you can make video calls. + 텔레그램이 영상 통화를 하기 위하여 기기의 마이크와 카메라에 접근이 필요합니다. 코멘트를 입력하실 수 있습니다 답신 전화 다시 전화 걸기 @@ -3213,7 +3261,7 @@ 맞춤 메시지... 맞춤 허용 %s님에게 텔레그램으로 전화 - Telegram Video Call to %s + %s님으로 부터의 영상 통화 지금은 텔레그램으로 전화하실 수 없습니다. 제 목소리가 울렸습니다 잡음이 들렸습니다 @@ -3222,15 +3270,20 @@ 상대의 목소리가 들리지 않았습니다 제 목소리가 상대에게 들리지 않았습니다 통화가 예기치 않게 종료되었습니다 - Video was distorted - Video was pixelated + 동영상이 왜곡됨 + 동영상이 깨져 보임 여기를 눌러 카메라를 켜세요 음소거 해제 + 또는 길게 눌러 말하기 + 실시간 참여중 + 관리자가 음소거함 + 음소거됨 + 듣기 전용 모드입니다 음소거 영상 시작 영상 중단 스피커 - Flip + 전환 영상 통화로 전환할까요? 전환 %s 님의 마이크가 꺼져 있습니다 @@ -3244,10 +3297,65 @@ Are you sure you want to video call **%1$s**? Video Call Reconnecting + 음성 대화 시작 + 음성 대화 + 이 그룹에서 음성 대화를 시작하겠습니까? + 음성 대화 관리 + 들어가기 + 참가자 %1$s명 말하는 중 + 참가자 %1$s명 말하는 중 + 참가자 %1$s명 말하는 중 + 참가자 %1$s명 말하는 중 + 참가자 %1$s명 말하는 중 + 참가자 %1$s명 말하는 중 + 말하는 중 + 듣는 중 + 초대됨 + 나가기 + 종료 + 마이크 음소거 + 정말 **%1$s**님을 음성 대화에서 음소거 하겠습니까? + 참가자 내보내기 + %1$s님을 그룹 대화에서 내보내시겠습니까? + **%1$s**님이 그룹에서 내보내졌습니다 + **%1$s** 님이 발언 할 수 있습니다 + **%1$s** 님은 대화에서 음소거 되었습니다 + 마이크 끄기 + 새 참가자 대화 가능 + 새 참가자 음소거 + 초대 링크 공유 + 음성 대화 종료 + 연결 중... + 음성 대화 나가기 + 정말 음성 대화를 나가시겠습니까? + 음성 대화 종료 + 정말 이 음성 대화를 종료하시겠습니까? + 음성 대화 종료 + 음성 대화 보기 + 음성 대화 + 음성 대화 참여 + 선택한 사용자는 이미 음성 대화에 참여 중입니다. + 죄송하지만, 익명 관리자로 음성 대화에 참여할 수 없습니다. + 음성 대화에 un1님이 un2님을 초대했습니다 + 음성 대화 참여 + 안녕하세요! 음성 대화에 참여해보세요: %1$s + 참가자 초대 + 추방 + 말하기 허용 + 초대할 참가자 검색... + 초대 링크 복사 + 초대 링크가 클립보드에 복사되었습니다. + 마이크 켜기 + Voice chat ended. Start a new one? + 참가자 추가 + **%1$s**님을 **%2$s**에 추가하시겠습니까? + **%1$s**님을 음성 대화에 초대했습니다 + 추가 + 눌러서 들어가기 - Message %1$s - Voice call %1$s - Video call %1$s + 메시지 보내기 %1$s + 음성 통화 걸기 %1$s + 영상 통화 걸기 %1$s 배경 %1$d개 삭제 배경 %1$d개 삭제 @@ -3327,6 +3435,12 @@ 참가자 %1$d명 참가자 %1$d명 참가자 %1$d명 + 참가자 %1$d명 + 참가자 %1$d명 + 참가자 %1$d명 + 참가자 %1$d명 + 참가자 %1$d명 + 참가자 %1$d명 외 %1$d명이 입력 중 외 %1$d명이 입력 중 외 %1$d명이 입력 중 @@ -3345,12 +3459,12 @@ 새로운 메시지 %1$d개 새로운 메시지 %1$d개 새로운 메시지 %1$d개 - %1$d messages unpinned - message unpinned - %1$d messages unpinned - %1$d messages unpinned - %1$d messages unpinned - %1$d messages unpinned + 메시지 %1$d개를 고정 해제했습니다 + 메시지 %1$d개를 고정 해제했습니다 + 메시지 %1$d개를 고정 해제했습니다 + 메시지 %1$d개를 고정 해제했습니다 + 메시지 %1$d개를 고정 해제했습니다 + 메시지 %1$d개를 고정 해제했습니다 메시지 %1$d개 메시지 %1$d개 메시지 %1$d개 @@ -3507,18 +3621,18 @@ %1$s회 공유 %1$s회 공유 %1$s회 공유 - %1$s public shares - %1$s public share - %1$s public shares - %1$s public shares - %1$s public shares - %1$s public shares - %1$s shared - %1$s shared - %1$s shared - %1$s shared - %1$s shared - %1$s shared + %1$s 공개 공유 + %1$s 공개 공유 + %1$s 공개 공유 + %1$s 공개 공유 + %1$s 공개 공유 + %1$s 공개 공유 + %1$s개 공유 + %1$s개 공유 + %1$s개 공유 + %1$s개 공유 + %1$s개 공유 + %1$s개 공유 스티커 묶음 %1$s개 스티커 묶음 %1$s개 스티커 묶음 %1$s개 @@ -3712,36 +3826,36 @@ 답글 %1$d 개 보기 답글 %1$d 개 보기 답글 %1$d 개 보기 - 답글 %1$d 개 - 답글 %1$d 개 - 답글 %1$d 개 - 답글 %1$d 개 - 답글 %1$d 개 - 답글 %1$d 개 + 답글 %1$d개 + 답글 %1$d개 + 답글 %1$d개 + 답글 %1$d개 + 답글 %1$d개 + 답글 %1$d개 코멘트 %1$d 개 코멘트 %1$d 개 코멘트 %1$d 개 코멘트 %1$d 개 코멘트 %1$d 개 코멘트 %1$d 개 - %1$d comments - %1$d comment - %1$d comments - %1$d comments - %1$d comments - %1$d comments - comments - comment - comments - comments - comments - comments - %1$d Pinned Messages - Pinned Message - %1$d Pinned Messages - %1$d Pinned Messages - %1$d Pinned Messages - %1$d Pinned Messages + %1$d 코멘트 + %1$d 코멘트 + %1$d 코멘트 + %1$d 코멘트 + %1$d 코멘트 + %1$d 코멘트 + 코멘트 + 코멘트 + 코멘트 + 코멘트 + 코멘트 + 코멘트 + %1$d개의 고정된 메시지 + %1$d개의 고정된 메시지 + %1$d개의 고정된 메시지 + %1$d개의 고정된 메시지 + %1$d개의 고정된 메시지 + %1$d개의 고정된 메시지 그룹 채널 @@ -3751,6 +3865,9 @@ Scheduled for %s 돌아가기 네비게이션 메뉴 열기 + 메뉴 열기 + 메뉴 닫기 + Open in photo viewer %2$s로 %1$s 옵션 더 보기 재생 @@ -3869,7 +3986,7 @@ 후면 카메라로 전환되었습니다 카메라가 켜져 있습니다 카메라가 꺼져 있습니다 - Pinned message list + 고정된 메시지 목록 yyyy년 MMMM yyyy년 MMM dd일 h:mm a @@ -3898,4 +4015,5 @@ \'오늘\' HH:mm\'에 알리기\' MMM d HH:mm\'에 알리기\' yyyy\'년\' M\'월\' d\'일\' HH:mm\'에 알림\' + 활성화 diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index 2abab421968..cd54cdd9de6 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -39,7 +39,7 @@ Account reset annuleren Iemand met toegang tot nummer **%1$s** heeft geprobeerd om je Telegram account te verwijderen en je twee-staps-verificatie wachtwoord te resetten.\n\nAls jij dit niet was, geef dan de code in die we zojuist per SMS hebben gestuurd. Je kunt dit ook annuleren door je telefoonnummer te *wijzigen naar een nummer waar je toegang tot hebt*. Account resetten - Account **%1$s** is actief en beveiligd met een wachtwoord, het verwijderen stellen we daarom 1 week uit.\n\nJe kunt dit proces ieder moment annuleren. + Account **%1$s** is actief en beveiligd met een wachtwoord, dus voor de veiligheid verwijderen we het pas over 1 week.\n\nJe kunt dit proces ieder moment annuleren. Je account kan gereset worden over: De actieve gebruiker heeft de recente poging om dit account te resetten geannuleerd. Probeer het over 7 dagen nog eens. RESET ACCOUNT @@ -53,8 +53,8 @@ Achternaam (optioneel) Registratie annuleren - %1$s is succesvol overgemaakt naar %2$s voor %3$s - %1$s is succesvol overgemaakt naar %2$s + Je hebt %1$s overgemaakt naar %2$s voor %3$s + Je hebt %1$s overgemaakt naar %2$s Afrekenen Verzendmethodes Sorry, afleveren op jouw adres is niet mogelijk. @@ -165,6 +165,7 @@ Vastzetten Losmaken Archiveren + Archief Dearchiveren Gearchiveerde chats Chat verwijderen @@ -172,7 +173,7 @@ Kies een chat Doorsturen naar Geheime foto - Geheime video + Tijdelijke video Geheime GIF %1$s gebruikt een oudere versie van Telegram, dus worden geheime foto\'s weergegeven in de compatibiliteitsmodus.\n\nZodra %2$s Telegram updatet werken foto\'s met timers voor 1 minuut of minder in de \'Druk en houd ingedrukt\'-modus en krijg je een bericht wanneer de andere partij een schermafdruk maakt. Berichten @@ -227,30 +228,30 @@ Je ontvangt veel nieuwe chats van mensen die geen contact van je zijn. Wil je deze chats **automatisch dempen** en **archiveren**? GA NAAR INSTELLINGEN Profiel openen - Open Channel - Open Group - Send Message - Mention - Notifications muted - Notifications muted for %1$s - Notifications unmuted - %1$d messages deleted - Message deleted - %1$d messages deleted - %1$d messages deleted - %1$d messages deleted - %1$d messages deleted - No Results + Open kanaal + Open groep + Stuur bericht + Vermelden + Meldingen stil + Meldingen stil voor %1$s + Meldingen aan + %1$d berichtend verwijderd + %1$d bericht verwijderd + %1$d berichtend verwijderd + %1$d berichtend verwijderd + %1$d berichtend verwijderd + %1$d berichtend verwijderd + Geen resultaten Geen resultaten - Try a new search. - Muziek - Bestanden - Links - Voice from all your chats will be shown here. - Media + Zoek opnieuw + Muziek van al je chats verschijnt hier + Bestanden van al je chats verschijnen hier + Links van al je chats verschijnen hier + Spraakberichten uit al je chats verschijnen hier + Media van al je chats verschijnen hier Chats - Message pinned - Message unpinned + Bericht vastgezet + Bericht losgemaakt Promoveren tot beheerder Beheerdersrechten aanpassen @@ -295,7 +296,7 @@ Gebruikers verwijderd door beheerders kunnen geen lid worden via uitnodigingslinks Nieuw kanaal Kanaalnaam - Contacten aan je kanaal toevoegen + Mensen aan je kanaal toevoegen Als je een permanente link instelt kunnen anderen je kanaal vinden en er lid van worden.\n\nJe kunt a-z, 0-9 en liggend streepje gebruiken.\nDe minimale lengte is 5 karakters. Als je een permanente link instelt kunnen anderen je groep vinden en er lid van worden.\n\nJe kunt a-z, 0-9 en liggend streepje gebruiken.\nDe minimale lengte is 5 karakters. Waarschuwing @@ -371,7 +372,7 @@ Kanaalvideo bijgewerkt Kanaalfoto verwijderd Kanaalnaam gewijzigd naar un2 - Het maximale aantal publieke gebruikersnamen is bereikt. Trek eerst een link van één van je oudere groepen of kanalen in, of gebruik de privé-variant. + Het maximale aantal publieke links is bereikt. Trek eerst een link van één van je oudere groepen of kanalen in, of gebruik de privé-variant. Eigenaar Beheerder Beheerder @@ -384,12 +385,12 @@ Uitnodigen via link Beheerder ontslaan Rechten aanpassen - Alleen kanaal-beheerders zien deze lijst. + Alleen kanaalbeheerders zien deze lijst. Andere Telegram-gebruikers kunnen lid worden van je groep door deze link te openen. Je kunt beheerders toevoegen om je te helpen je kanaal te beheren. Druk en houd ingedrukt om beheerders te verwijderen. Lid worden van kanaal \'%1$s\'? Sorry, deze chat is niet beschikbaar. - Sorry, you can\'t access this chat because you were banned by an admin. + Sorry, je kunt niet bij deze chat omdat een beheerder je geblokkeerd heeft. Helaas ben je geblokkeerd van deelname in publieke groepen. Sorry, deze chat is niet beschikbaar. %1$s toevoegen aan het kanaal? @@ -444,7 +445,7 @@ Berichten verwijderen Verwijder berichten Beheerders toevoegen - Send Anonymously + Anoniem blijven Beheerder ontslaan Eigenaarschap overdragen Eigenaarschap overdragen @@ -475,7 +476,7 @@ Berichten versturen Media versturen Polls sturen - Stickers & GIF\'s versturen + Stickers en GIF\'s sturen Link-voorbeeld sturen Chatinformatie wijzigen Berichten vastzetten @@ -535,13 +536,13 @@ BEHEERDER MAKEN %1$s zal verwijderd worden als beheerder als je een beperking oplegt. Discussie - View discussion + Discussie weergeven Voeg een groepschat toe voor opmerkingen. Gekoppeld kanaal - Select a group chat that will host comments from your channel. + Kies een groepschat waar de opmerkingen voor je kanaal naartoe gaan. Alles wat je plaatst in het kanaal zal worden doorgestuurd naar deze groep. - **%1$s** is selected as the group that hosts comments for your channel. - **%1$s** koppelt de groep als discussiegroep + **%1$s** is gekozen als groep waar opmerkingen voor je kanaal naartoe gaan. + Groep gekoppeld als discussiegroep voor %1$s. Alle nieuwe berichten die je plaatst in dit kanaal worden doorgestuurd naar de groep. Maak een nieuwe groep Groep ontkoppelen @@ -566,7 +567,8 @@ Tempolimiet ingeschakeld. Je kunt niet meer dan 1 bericht tegelijkertijd sturen. Tempolimiet ingeschakeld. Je kunt niet meer dan 1 item selecteren. Sorry, deze tekst is te lang om als 1 bericht te sturen.\n\nTempolimiet is ingeschakeld, je kunt niet meer dan 1 bericht tegelijkertijd sturen. - **%1$s** promoted to admin + **%1$s** gepromoveerd tot beheerder + **%1$s** verwijderd van **%2$s** Nieuwe poll Nieuwe quiz @@ -639,7 +641,7 @@ Recente gebeurtenissen Alle gebeurtenissen - Geselecteerde gebeurtenissen + geselecteerde gebeurtenissen Alle beheerders **Nog geen gebeurtenissen**\n\nBeheerders en leden\nhebben geen acties uitgevoerd\nin de afgelopen 48 uur. **Nog geen gebeurtenissen**\n\nBeheerders\nhebben geen acties uitgevoerd\nin de afgelopen 48 uur. @@ -716,8 +718,9 @@ Berichten wijzigen Berichten verwijderen Beheerders toevoegen - Send anonymously + Anoniem blijven Leden blokkeren + Spraakchats beheren Leden toevoegen Titel: %1$s Titel @@ -732,8 +735,15 @@ Gewijzigde berichten Vastgezette berichten Vertrokken leden + Spraakchats un1 heeft tempolimiet ingesteld op %1$s un1 heeft tempolimiet uitgeschakeld + un1 startte een spraakchat + un1 beëindigde de spraakchat + un1 heeft un2 gedempt in een spraakchat + un1 heeft het geluid van un2 ingeschakeld. + un1 gaf toestemming aan nieuwe spraakchatleden om te praten. + un1 heeft nieuwe deelnemers van de spraakchat gedempt Nieuwe verzendlijst Naam van lijst @@ -852,7 +862,7 @@ SLEEP OM TE ANNULEREN Opslaan in Downloads GIF opslaan - GIF verwijderen? + GIF verwijderen van deze sectie? Opslaan in muziek Delen Vertaling toepassen @@ -886,7 +896,7 @@ VOEG %1$s TOE AAN CONTACTEN CONTACT BEKIJKEN **%1$s** echt blokkeren om je berichten te sturen en je te bellen via Telegram? - Do you want to block messages from **%1$s**? + Echt berichten van **%1$s** blokkeren? "Spam van deze gebruiker echt melden? " "Spam van deze groep echt melden? " "Spam van dit kanaal echt melden? " @@ -899,12 +909,12 @@ Tik hier om opgeslagen GIF\'s te bekijken Vastzetten Alle leden informeren - Also pin for %1$s + Ook vastzetten voor %1$s Losmaken Bericht vastzetten Bericht losmaken - Do you want to pin an older message while leaving a more recent one pinned? - Wil je dit bericht vastzetten? + Wil je een ouder bericht vastzetten maar ook een nieuwer bericht vastgezet laten? + Dit bericht vastzetten in de groep? Wil je dit bericht vastzetten? Wil je dit bericht vastzetten bovenaan de chat? Wil je dit bericht losmaken? @@ -929,12 +939,19 @@ Overig Beschrijving Vastgezet bericht - Previous Message + Vorig bericht Vastgezette poll gewijzigd Bericht wijzigen Wijzig onderschrift Media vervangen + Foto bewerken + Video bewerken + Foto vervangen + Video vervangen + Media vervangen + Bestand vervangen + Audiobestand vervangen Scrollen voor bots %1$s Wijzigen kan niet meer. @@ -1003,6 +1020,8 @@ Tik voor foto, hou vast voor video Tik om als lijst weer te geven. Stuur zonder geluid + Sturen als nieuwe foto + Foto vervangen Stuur nu Plan opnieuw Vandaag @@ -1048,28 +1067,28 @@ m u w - to private messages and groups - Transfer Bot Ownership - This will transfer the **full owner** rights for the bot to the selected user. - Change Owner - You can transfer bot only if you have: - Leave a comment - Comments - Comment - Replies - No comments here yet... - No replies here yet... - View in chat - Send anonymously - Discussion started - View Thread - Choose date - This chat helps you keep track of replies to your comments in Channels. - Sorry, this post has been removed from the discussion group. - UNPIN ALL MESSAGES - HIDE PINNED MESSAGES - Pinned messages hidden - Pinned messages will be shown again if a new message is pinned. + naar privéberichten en groepen + Eigenaarschap van bot overdragen + Hiermeer draag je het **volledige eigenaarschap** van de bot over naar de gekozen gebruiker. + Eigenaarschap overdragen + Je kan deze bot alleen overdragen als je het volgende hebt: + Opmerking toevoegen + Opmerkingen + Opmerking + Antwoorden + Nog geen opmerkingen + Nog geen antwoorden + Bekijk in chat + Anoniem verzenden + Discussie gestart + Gesprek weergeven + Kies datum + Via deze chat kun je de antwoorden op jouw opmerkingen in kanalen volgen. + Sorry, deze post is verwijderd uit de discussiegroep + ALLE BERICHTEN LOSMAKEN + VASTGEZETTE BERICHTEN VERBERGEN + Vastgezette berichten verborgen + Vastgezette berichten worden opnieuw weergegeven als een nieuw bericht is vastgezet. %1$s heeft de zelfvernietigingstimer ingesteld op %2$s Je hebt de zelfvernietigingstimer ingesteld op %1$s @@ -1116,7 +1135,7 @@ %1$s heeft een bestand gestuurd naar de groep %2$s %1$s heeft een GIF gestuurd naar de groep %2$s %1$s heeft een factuur naar de groep %2$s voor %3$s gestuurd - %1$s heeft een spraakbericht gestuurd naar de groep %2$s + %1$s stuurde een spraakbericht %2$s %1$s heeft een videobericht gestuurd naar de groep %2$s %1$s heeft een muziekbestand gestuurd naar de groep %2$s %1$s heeft een sticker gestuurd naar de groep %2$s @@ -1126,13 +1145,17 @@ %1$s heeft de groepsfoto voor %2$s aangepast %1$s heeft de groepsvideo voor %2$s aangepast %1$s heeft %3$s uitgenodigd voor de groep %2$s + %1$s nodigde %3$s uit voor een spraakchat in %2$s + %1$s nodigde je uit voor een spraakchat in %2$s + %1$s startte een spraakchat in %2$s + %1$s beëindigde de spraakchat in %2$s %1$s is terug in de groep %2$s %1$s is nu lid van de groep %2$s %1$s heeft %3$s verwijderd uit de groep %2$s %1$s heeft je verwijderd uit de groep %2$s %1$s heeft de groep %2$s verlaten %1$s heeft nu Telegram! - %1$s,\nEr is op je account ingelogd vanaf een nieuw apparaat op %2$s\n\nApparaat: %3$s\nLocatie: %4$s\n\nAls jij dit niet was, kun je die sessie beëindigen via Instellingen - Privacy en veiligheid - Sessies.\n\nAls je dat denkt dat iemand anders zonder jouw toestemming is ingelogd kun je twee-staps-verificatie activeren via instellingen - privacy en veiligheid.\n\nBedankt,\nHet Telegram-team + %1$s,\nEr is op je account ingelogd vanaf een nieuw apparaat op %2$s\n\nApparaat: %3$s\nLocatie: %4$s\n\nAls jij dit niet was, kun je die sessie beëindigen via Instellingen - Apparaten.\n\nAls je dat denkt dat iemand anders zonder jouw toestemming is ingelogd kun je twee-staps-verificatie activeren via instellingen - privacy en veiligheid.\n\nBedankt,\nHet Telegram-team %1$s heeft zijn/haar profielfoto gewijzigd %1$s is nu lid van de groep %2$s via uitnodigingslink %1$s heeft %3$s naar de groep %2$s gestuurd @@ -1158,7 +1181,7 @@ %1$s heeft bestand vastgezet in de groep %2$s %1$s heeft sticker vastgezet in de groep %2$s %1$s heeft een %3$s sticker vastgezet in de groep %2$s - %1$s heeft spraakbericht vastgezet in de groep %2$s + %1$s zette een spraakbericht vast in %2$s %1$s heeft videobericht vastgezet in de groep %2$s %1$s heeft een contact %3$s vastgezet in de groep %2$s %1$s heeft locatie vastgezet in de groep %2$s @@ -1185,25 +1208,25 @@ %1$s heeft een live-locatie vastgezet %1$s heeft GIF vastgezet %1$s heeft muziekbestand vastgezet - %1$s pinned \"%2$s\" - %1$s pinned a message - %1$s pinned a poll %2$s - %1$s pinned a quiz %2$s - %1$s pinned a photo - %1$s pinned a game - %1$s pinned a game score - %1$s pinned a video - %1$s pinned a file - %1$s pinned an invoice - %1$s pinned a sticker - %1$s pinned a %2$s sticker - %1$s pinned a voice message - %1$s pinned a video message - %1$s pinned a contact %2$s - %1$s pinned a map - %1$s pinned a live location - %1$s pinned a GIF - %1$s pinned an audio file + %1$s heeft \"%2$s\" vastgezet + %1$s zette een bericht vast + %1$s heeft de poll %2$s vastgezet + %1$s heeft de quiz %2$s vastgezet + %1$s zette een foto vast + %1$s zette een spel vast + %1$s zette een spelscore vast + %1$s zette een video vast + %1$s zette een bestand vast + %1$s zette een factuur vast + %1$s zette een sticker vast + %1$s heeft sticker %2$s vastgezet + %1$s zette een spraakbericht vast + \n%1$s zette een videobericht vast + %1$s heeft contact %2$s vastgezet + %1$s zette een kaart vast + \n%1$s zette een Live-locatie vast + \n%1$s zette een GIF vast + \n%1$s zette een audiobestand vast Telegram Contact kiezen @@ -1240,15 +1263,15 @@ Sorteren op laatst-gezien Voeg %1$s toe Telefoonnummer - You have no contacts on Telegram yet - Invite friends to try Telegram - Find people nearby to chat with - Search people by username - New contact - The phone number **%1$s** is not in your contact list. Do you want to add it? - Add contact + Je hebt nog geen contacten op Telegram + Nodig vrienden uit om Telegram te proberen + Vind mensen dichtbij om mee te chatten + Zoek mensen op gebruikersnaam + Nieuw contact + Telefoonnummer **%1$s** staat niet in je contacten, toevoegen? + Voeg contact toe - Mensen toevoegen + Mensen toevoegen... Je kan meer leden toevoegen nadat je de groep hebt aangemaakt. Groepsnaam Groepsnaam @@ -1262,6 +1285,7 @@ LID WORDEN Link gekopieerd naar klembord. Link gekopiëerd naar klembord.\nDeze link werkt alleen voor leden van deze chat. + This link will only work for members of this chat. Je kunt dit bericht niet openen omdat je geen lid bent van de chat waar dit bericht is geplaatst. Nummer gekopieerd naar klembord E-mail gekopieerd naar klembord @@ -1284,7 +1308,7 @@ Instellingen Abonnee toevoegen Lid toevoegen - Beheerders instellen + Beheerders toevoegen LID BEPERKEN Groep verwijderen en verlaten Verwijder en verlaat groep @@ -1296,7 +1320,7 @@ Opwaarderen naar supergroep Waarschuwing Groep echt omzetten naar supergroep? Je kunt dit niet ongedaan maken. - "**Ledenlimiet bereikt.**\n\nWil je extra functies en een hogere limiet? Waardeer op naar een supergroep:\n\n• Supergroepen hebben maximaal %1$s\n• Nieuwe leden zien de hele geschiedenis\n• Gewiste berichten gelde voor iedereen\n• Beheerders kunnen een groepsbeschrijving instellen\n• Maker kan een publieke groepslink instellen " + "**Ledenlimiet bereikt.**\n\nWil je extra functies en een hogere limiet? Waardeer op naar een supergroep:\n\n• Supergroepen hebben maximaal %1$s\n• Nieuwe leden zien de hele geschiedenis\n• Gewiste berichten gelden voor iedereen\n• Beheerders kunnen een groepsbeschrijving instellen\n• Maker kan een publieke groepslink instellen " **Supergroepen:**\n\n• Nieuwe leden zien de hele geschiedenis\n• Gewiste berichten gelden voor iedereen\n• Beheerders kunnen een groepsbeschrijving instellen\n• Maker kan een publieke groepslink instellen **Let op:** Je kunt dit niet ongedaan maken. @@ -1307,7 +1331,7 @@ %1$s is nog geen lid, uitnodigen? Nodig uit Blokkeren - BLOCK AND DELETE REPLIES + BLOKKEER EN VERWIJDER ANTWOORDEN Blokkeer Blokkeer gebruiker Blokkeer gebruikers @@ -1366,7 +1390,7 @@ Sorry, deze gebruikersnaam is ongeldig. Je naam moet minimaal 5 tekens hebben. Je naam mag niet langer zijn dan 32 tekens. - Sorry, begincijfers zijn niet toegestaan. + Gebruikersnamen kunnen niet met een nummer beginnen. Je kan een gebruikersnaam kiezen voor **Telegram**. Hiermee kunnen anderen je vinden en contact met je opnemen zonder je telefoonnummer te weten.\n\nJe mag **a–z**, **0–9** en liggend streepje gebruiken. De minimale lengte is **5** tekens. Deze link opent een chat met je:\n%1$s Gebruikersnaam controleren. @@ -1814,6 +1838,10 @@ Chatgeluiden Standaard Standaard + Standaard + In-app standaard + %1$s in-app + Stil Slimme meldingen Uitzonderingen Uitzondering toevoegen @@ -1960,7 +1988,7 @@ Berekenen... Bestanden Foto\'s - Spraak/Video-berichten + Spraak- en videoberichten Video\'s Muziek GIFs @@ -2160,7 +2188,7 @@ Vietnamees Actieve sessies - Huidige sessie + Dit apparaat Geen andere actieve sessies Je kunt in Telegram inloggen vanaf andere apparaten (mobiel, tablet, desktop) met hetzelfde telefoonnummer. Al je data zal direct worden gesynchroniseerd. Actieve sessies @@ -2230,7 +2258,7 @@ Bots Chats toevoegen Wacht even terwijl we deze map voor je vullen... - Geen chats gevonden + Map is leeg Geen chats die momenteel horen bij deze map. Nieuwe map Geen chats @@ -2317,7 +2345,7 @@ Groepen Links Muziek - Spraakberichten + Spraak GIF\'s Gedeelde bestanden Gedeelde content @@ -2381,8 +2409,8 @@ zojuist bijgewerkt Jij en %1$s %1$s aan het delen met %2$s - %1$s sharing with %2$s - %1$s sharing with %2$s + %1$s delen met %2$s + %1$s delen met %2$s ALLES STOPPEN Je deelt je live-locatie met %1$s Kies hoelang je je nauwkeurige locatie met %1$s wilt delen. @@ -2411,19 +2439,19 @@ Stel deze locatie in Mensen kunnen je groep vinden in de \"Mensen Dichtbij\"-sectie Plaatsen in de buurt - Proximity alert - Notify when %1$s is within %2$s - Notify when someone is within %1$s - You are already closer than %1$s - Share Location - Share - For the alert to work, please share your live location in this chat. - Alert when %1$s is close - Alert when other members of the group are close - Proximity alert set - We will notify you once %1$s is within %2$s from you. - We will notify you once someone is within %1$s from you. - Proximity alert cancelled + Nabijheidsmelding + Melden als %1$s binnen %2$s is + Melden indien iemand binnen %1$s is + Je bent al binnen %1$s + Locatie delen + Delen + Deel je Live-locatie in deze chat om de melding te activeren + Melden als %1$s dichtbij is + Melden als andere groepsleden in de buurt zijn + Nabijheidsmelding ingesteld + We sturen je een melding als %1$s binnen een straal van %2$s is. + We sturen je een melding als iemand binnen een straal van %1$s is. + Nabijheidsmelding geannuleerd Weergeven als lijst Weergeven als rooster @@ -2529,43 +2557,43 @@ Dit is nu de hoofdkanaalvideo. Dit is nu de hoofdgroepsfoto. Dit is nu de hoofdgroepsvideo. - Photo saved to gallery - Video saved to gallery - Photo saved to downloads - Video saved to downloads - GIF saved to downloads - File saved to music - File saved to downloads - %1$d files saved to downloads - File saved to downloads - %1$d files saved to downloads - %1$d files saved to downloads - %1$d files saved to downloads - %1$d files saved to downloads - %1$d photos saved to gallery - Photo saved to gallery - %1$d photos saved to gallery - %1$d photos saved to gallery - %1$d photos saved to gallery - %1$d photos saved to gallery - %1$d videos saved to gallery - Video saved to gallery - %1$d videos saved to gallery - %1$d videos saved to gallery - %1$d videos saved to gallery - %1$d videos saved to gallery - %1$d files saved to music - File saved to music - %1$d files saved to music - %1$d files saved to music - %1$d files saved to music - %1$d files saved to music - %1$d items saved to gallery - One item saved to gallery - %1$d items saved to gallery - %1$d items saved to gallery - %1$d items saved to gallery - %1$d items saved to gallery + Foto opgeslagen in galerij + Video opgeslagen in galerij + Foto opgeslagen in downloads + Video opgeslagen in downloads + GIF opgeslagen in downloads + Bestand opgeslagen in muziek + Bestand opgeslagen in downloads + %1$d bestanden opgeslagen in downloads + %1$d bestand opgeslagen in downloads + %1$d bestanden opgeslagen in downloads + %1$d bestanden opgeslagen in downloads + %1$d bestanden opgeslagen in downloads + %1$d bestanden opgeslagen in downloads + %1$d foto\'s opgeslagen in galerij + %1$d foto opgeslagen in galerij + %1$d foto\'s opgeslagen in galerij + %1$d foto\'s opgeslagen in galerij + %1$d foto\'s opgeslagen in galerij + %1$d foto\'s opgeslagen in galerij + %1$d video\'s opgeslagen in galerij + %1$d video opgeslagen in galerij + %1$d video\'s opgeslagen in galerij + %1$d video\'s opgeslagen in galerij + %1$d video\'s opgeslagen in galerij + %1$d video\'s opgeslagen in galerij + %1$d bestanden opgeslagen in muziek + %1$d bestand opgeslagen in muziek + %1$d bestanden opgeslagen in muziek + %1$d bestanden opgeslagen in muziek + %1$d bestanden opgeslagen in muziek + %1$d bestanden opgeslagen in muziek + %1$d items in galerij opgeslagen + %1$d item in galerij opgeslagen + %1$d items in galerij opgeslagen + %1$d items in galerij opgeslagen + %1$d items in galerij opgeslagen + %1$d items in galerij opgeslagen Twee-staps-verificatie Twee-staps-verificatie @@ -2574,6 +2602,7 @@ Terug naar instellingen Terug naar Passport Wachtwoord instellen + Show password Extra wachtwoord instellen Naast de code die je per SMS ontvangt kun je een extra wachtwoord instellen voor als je inlogt op een nieuw apparaat. Je wachtwoord @@ -2630,7 +2659,7 @@ Herstelcode We hebben een herstelcode naar je opgegeven e-mailadres gestuurd:\n\n%1$s Controleer je E-mail en geef de 6-cijferige code in die we je hebben gestuurd. - Heb je geen toegang tot je e-mailadres %1$s? + Geen toegang tot %1$s? Geen toegang tot je e-mail? Bij verlies van je wachtwoord zul je je account moeten resetten. ACCOUNT RESETTEN @@ -2654,6 +2683,7 @@ Opslag- en datagebruik Opslaggebruik Datagebruik + Opslagpad Mobiel Wi-Fi Roaming @@ -2676,8 +2706,8 @@ Privacy en veiligheid Privacy Laatst gezien en online - Profielfoto - Wie kan mijn profielfoto zien + Profielfoto\'s + Wie kan mijn profielfotos en -video\'s zien? Je kunt nauwkeurig beperken wie je profielfoto kan zien. Je kunt gebruikers of groepen toevoegen als uitzondering op de instelling hierboven. Telefoonnummer @@ -2849,9 +2879,17 @@ un1 is terug in de groep un1 is lid van de groep Je keerde terug naar de groep - un1 is now within %1$s from you - You are now within %1$s from un1 - un1 is now within %1$s from un2 + un1 is nu binnen %1$s van je + Je bent nu binnen %1$s van un1 + un1 is nu binnen %1$s van un2 + un1 heeft je uitgenodigd voor deze groep + un1 heeft je uitgenodigd voor dit kanaal + un1 startte een spraakchat + Je startte een spraakchat + Spraakchat beëindigt (%s) + un1 nodigde un2 uit voor de spraakchat + Je hebt un2 uitgenodigd voor de spraakchat. + un1 heeft je uitgenodigd voor de spraakchat Je hebt deze bot toegestaan je berichten te sturen door in te loggen op %1$s. %1$s heeft de volgende documenten ontvangen: %2$s Persoonlijke gegevens @@ -2867,7 +2905,7 @@ Huurovereenkomst Telefoonnummer E-mailadres - Dit bericht wordt niet ondersteund door jouw versie van Telegram. Werk Telegram bij om dit bericht te bekijken: https://telegram.org/update + Dit bericht wordt niet ondersteund door jouw versie van Telegram. Update om dit bericht te bekijken: https://telegram.org/update Foto Video Zelfvernietigende foto @@ -2908,9 +2946,9 @@ Log in op Telegram om Telegram Passport te gebruiken. Dit nummer is geblokkeerd. Code verlopen, log opnieuw in. - Te veel pogingen. Probeer het later opnieuw. + Te veel pogingen, probeer het later opnieuw. Te veel pogingen, probeer het over %1$s opnieuw - Ongeldige code + Ongeldige code, probeer het opnieuw Je hebt in korte tijd je account veelvuldig verwijderd en opnieuw aangemaakt. Probeer het over een aantal dagen nog eens. Ongeldige voornaam Ongeldige achternaam @@ -2946,7 +2984,7 @@ Chat met **%1$s** echt wissen? Echt **%1$s** blokkeren en de chat verwijderen? " **Bewaarde berichten** echt verwijderen?" - Geheime chat met **%1$s** echt wissen? + Weet je zeker dat je de geheime chat met **%1$s** wilt verwijderen? Chat **%1$s** echt wissen? Wis Cloud-concepten Echt alle Cloud-conceptberichten wissen? @@ -3025,10 +3063,13 @@ Telegram heeft toegang tot je camera nodig zodat je foto\'s en video\'s kunt maken. Schakel dit in via instellingen. Telegram heeft toegang tot je locatie nodig om deze te kunnen delen met je vrienden. Telegram heeft toegang tot je locatie nodig. - Telegram heeft de toestemming \'over andere apps tekenen\' nodig om video\'s af te spelen in Picture-in-Picture-modus. + Telegram heeft de toestemming \'over andere apps tekenen\' nodig om video\'s af te spelen in beeld-in-beeld-modus. + Met overlay-modus kun je Push-To-Talk gebruiken en zien wie er aan het praten is zelfs als je Telegram niet in de voorgrond hebt. INSTELLINGEN Sta Telegram toe om weer te kunnen geven op het vergrendelscherm om ervoor te zorgen dat oproepen goed werken. - To share your live location in this chat, Telegram needs access to your location all the time, including while the app is in the background.\n\nWe will access your location only for the duration you choose, and you can stop sharing it any time. We won\'t use your location for any purpose other than sharing it in this chat. + Om je Live-locatie in deze chat te kunnen delen heeft Telegram constante toegang tot je locatie nodig, ook als deze op de achtergrond draait.\n\nWe gebruiken je locatie alleen voor de periode die jij instelt en je kunt het delen op ieder moment stoppen. We maken alleen gebruik van je locatiegegevens voor het delen ervan in deze chat. + Beeld-in-beeld + Spraakchat-overlay Groei Volgers @@ -3104,13 +3145,13 @@ Profiel openen Vandaag Gisteren - Views - Public Shares - Private Shares - View Stats - View Channel Stats - Message Statistics - Open Message + Weergaves + Publiek gedeeld + Prive gedeeld + Stats weergeven + Kanaaalstatistieken weergeven + Berichtstatistieken + Open bericht Telegram Snel @@ -3127,7 +3168,7 @@ Begin met chatten Accountinstellingen - Minder data voor oproepen gebruiken + Data besparen bij oproepen Inkomende oproep Verbinden Encryptiesleutels uitwisselen @@ -3141,9 +3182,14 @@ Telegram-oproep Telegram-video-oproep Telegram-oproep bezig + Spraakchat bezig Ophangen Er is al een oproep actief - Er is al een oproep actief met **%1$s**. Wil je deze oproep beëindigen en een nieuwe oproep starten met **%2$s**? + Oproep met **%1$s** beëindigen en een nieuwe starten met **%2$s**? + Oproep met **%1$s** stoppen en spraakchat starten in **%2$s**? + Een andere spraakchat is actief + Spraakchat in **%1$s** verlaten en nu starten in **%2$s**? + Spraakchat in **%1$s** verlaten en **%2$s** bellen? Oproepen Beltoon Je kunt een aangepaste beltoon instellen voor Telegram-oproepen van dit contact. @@ -3160,7 +3206,9 @@ Opnemen Weigeren Je bent offline, maak verbinding met het internet om een oproep te starten. + Je bent momenteel offline. Maak verbinding met het internet om deel te nemen aan spraakchats. Vliegtuigmodus is actief, schakel vliegtuigmodus uit of verbind met Wi-Fi om een oproep te starten + Je hebt vliegtuigmodus ingeschakeld. Schakel vliegtuigmodus uit of verbind met Wi-Fi om deel te nemen aan spraakchats. Offline Vliegtuigmodus Instellingen @@ -3175,15 +3223,15 @@ Geannuleerde oproep Geweigerde video-oproep %1$s (%2$s) - Je hebt nog geen oproepen gedaan. + Nog geen oproepen... **%1$s** maakt gebruik van een niet-compatibel protocol voor spraakoproepen en moet eerst een update uitvoeren. **%1$s** heeft nog geen ondersteuning voor spraakoproepen en zal eerst een update moeten uitvoeren. Sorry, **%1$s** gebruikt een oude versie van Telegram die geen videogesprekken ondersteunt. - Make a voice call + Voer een spraakoproep Beoordeel de kwaliteit van je Telegram-oproep. Telegram heeft toegang tot je microfoon nodig zodat je kunt bellen. Telegram heeft toegang nodig tot je microfoon en camera, zodat je video-oproepen kunt doen. - Opmerking toevoegen + Optionele opmerking toevoegen Terugbellen Herhaal Standaard @@ -3226,6 +3274,11 @@ Video was korrelig Tik hier om je camera aan te zetten Geluid aan + of vasthouden en praten + Je bent live + Gedempt door een beheerder + Gedempt + Je kan nu alleen luisteren Geluid uit Camera aan Camera uit @@ -3239,11 +3292,66 @@ Weigeren Opnieuw proberen Video - Are you sure you want to call **%1$s**? - Voice Call - Are you sure you want to video call **%1$s**? - Video Call + Echt bellen met %1$s**? + Spraakoproep + Echt een video-oproep starten met %1$s**? + Video-oproep Opnieuw verbinden + Spraakchat starten + Spraakchat + Wil je een spraakchat starten in deze groep? + Spraakchats beheren + Deelnemen + %1$s deelnemers spreken + %1$s deelnemer spreekt + %1$s deelnemers spreken + %1$s deelnemers spreken + %1$s deelnemers spreken + %1$s deelnemers spreken + aan het spreken + aan het luisteren + uitgenodigd + Verlaten + Beëindigen + Microfoon dempen + Weet je zeker dat je **%1$s** wilt dempen in deze spraakchat? + Lid verwijderen + Wil je %1$s van de groepschat verwijderen? + **%1$s** verwijderd van de groep. + **%1$s** kan nu spreken. + **%1$s** is nu gedempt in deze chat. + Dempen + Nieuwe deelnemers kunnen spreken + Nieuwe deelnemers zijn gedempt + Uitnodigingslink delen + Spraakchat beëindigen + Verbinden... + Spraakchat verlaten + Weet je zeker dat je deze spraakchat wilt verlaten? + Spraakchat beëindigen + Weet je zeker dat je deze spraakchat wilt beëindigen? + Spraakchat beëindigen + SPRAAKCHAT + Spraakchat + Spraakchat openen + De geselecteerde gebruiker is al in deze spraakchat. + Sorry, je kan niet deelnemen aan spraakchats als een anonieme beheerder. + un1 nodigde un2 uit voor de spraakchat + Deelnemen aan spraakchat + Hoi! Neem deel aan onze spraakchat: %1$s + Leden uitnodigen + Verwijderen + Spreken toestaan + Zoek leden om uit te nodigen... + Uitnodigingslink kopiëren + Uitnodigingslink gekopieerd naar klembord. + Geluid aan + Spraakchat beëindigt. Een nieuwe starten? + Lid toevoegen + Wil je **%1$s** toevoegen aan **%2$s**? + Je hebt **%1$s** uitgenodigd voor de spraakchat + Toevoegen + Tik om deel te nemen Bericht naar %1$s Spraakoproep naar %1$s @@ -3327,6 +3435,12 @@ %1$d leden %1$d leden %1$d leden + %1$d deelnemers + %1$d deelnemer + %1$d deelnemers + %1$d deelnemers + %1$d deelnemers + %1$d deelnemers en %1$d meer zijn aan het typen en %1$d meer is aan het typen en %1$d meer zijn aan het typen @@ -3345,12 +3459,12 @@ %1$d nieuwe berichten %1$d nieuwe berichten %1$d nieuwe berichten - %1$d messages unpinned - message unpinned - %1$d messages unpinned - %1$d messages unpinned - %1$d messages unpinned - %1$d messages unpinned + %1$d berichten losgemaakt + Bericht losgemaakt + %1$d berichten losgemaakt + %1$d berichten losgemaakt + %1$d berichten losgemaakt + %1$d berichten losgemaakt %1$d berichten %1$d bericht %1$d berichten @@ -3507,18 +3621,18 @@ %1$s keer gedeeld %1$s keer gedeeld %1$s keer gedeeld - %1$s public shares - %1$s public share - %1$s public shares - %1$s public shares - %1$s public shares - %1$s public shares - %1$s shared - %1$s shared - %1$s shared - %1$s shared - %1$s shared - %1$s shared + %1$s publiek gedeeld + %1$s publiek gedeeld + %1$s publiek gedeeld + %1$s publiek gedeeld + %1$s publiek gedeeld + %1$s publiek gedeeld + %1$s gedeeld + %1$s gedeeld + %1$s gedeeld + %1$s gedeeld + %1$s gedeeld + %1$s gedeeld %1$s stickerbundels %1$s stickerbundel %1$s stickerbundels @@ -3706,42 +3820,42 @@ %1$d van %2$d geselecteerd %1$d van %2$d geselecteerd %1$d van %2$d geselecteerd - View %1$d Replies - View %1$d Reply - View %1$d Replies - View %1$d Replies - View %1$d Replies - View %1$d Replies - %1$d Replies - %1$d Reply - %1$d Replies - %1$d Replies - %1$d Replies - %1$d Replies - %1$d Comments - %1$d Comment - %1$d Comments - %1$d Comments - %1$d Comments - %1$d Comments - %1$d comments - %1$d comment - %1$d comments - %1$d comments - %1$d comments - %1$d comments - comments - comment - comments - comments - comments - comments - %1$d Pinned Messages - Pinned Message - %1$d Pinned Messages - %1$d Pinned Messages - %1$d Pinned Messages - %1$d Pinned Messages + %1$d antwoorden bekijken + %1$d antwoord bekijken + %1$d antwoorden bekijken + %1$d antwoorden bekijken + %1$d antwoorden bekijken + %1$d antwoorden bekijken + %1$d antwoorden + %1$d antwoord + %1$d antwoorden + %1$d antwoorden + %1$d antwoorden + %1$d antwoorden + %1$d Opmerkingen + %1$d Opmerking + %1$d Opmerkingen + %1$d Opmerkingen + %1$d Opmerkingen + %1$d Opmerkingen + %1$d opmerkingen + %1$d opmerking + %1$d opmerkingen + %1$d opmerkingen + %1$d opmerkingen + %1$d opmerkingen + opmerkingen + opmerking + opmerkingen + opmerkingen + opmerkingen + opmerkingen + %1$d vastgezette berichten + %1$d vastgezet bericht + %1$d vastgezette berichten + %1$d vastgezette berichten + %1$d vastgezette berichten + %1$d vastgezette berichten Groep Kanaal @@ -3751,6 +3865,9 @@ Gepland om %s Ga terug Navigatiemenu openen + Menu openen + Menu sluiten + Open in photo viewer %2$s door %1$s Meer opties Afspelen @@ -3815,7 +3932,7 @@ Titel Titel Mijn locatie - Notify when people sharing location are in range + Melden als mensen die hun locatie delen in de buurt zijn Videokwaliteit Beelverhouding Nog een foto nemen @@ -3869,7 +3986,7 @@ Overgeschakeld naar de achtercamera De camera staat aan De camera staat uit - Pinned message list + Vastgezette berichtenlijst MMMM yyyy dd MMM yyyy, h:mm a @@ -3898,4 +4015,5 @@ \'Herinner vandaag om HH:mm \'Herinner op\' d MMM \'om\' HH:mm \'Herinner op\' d MMM yyyy \'om\' HH:mm + Inschakelen diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index c54ad83e5e2..35b4566c1f1 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -9,7 +9,7 @@ Continuar em Português Seu Número - Por favor, confirme o código de seu país e digite seu número de telefone. + Por favor, confirme o código do seu país e digite o seu número de telefone. Escolha um país Código do país inválido Esta conta já está conectada a partir deste aplicativo. @@ -39,7 +39,7 @@ Cancelar Exclusão da Conta Alguém com acesso ao número **%1$s** solicitou excluir a sua conta do Telegram e redefinir a sua senha de Verificação em Duas Etapas.\n\nSe não foi você, digite o código que acabamos de enviar via SMS. Você também pode cancelar isso *alterando o seu número de telefone*. Apagar conta - Como a conta %1$s está ativa e protegida por uma senha, iremos apagá-la em 1 semana por questões de segurança.\n\nVocê pode cancelar esse processo a qualquer momento. + Como a conta %1$s está ativa e protegida por uma senha, ela será apagada em 1 semana. Esse tempo é necessário por questões de segurança.\n\nVocê pode cancelar esse processo a qualquer momento. Você poderá redefinir a sua conta em: As suas tentativas recentes de redefinir esta conta foram canceladas pelo usuário ativo. Por favor, tente novamente em 7 dias. APAGAR CONTA @@ -47,7 +47,7 @@ O processo de exclusão da sua conta %1$s foi cancelado. Você pode fechar esta janela agora. Seu código de login é **%1$s**. Digite ele no app do Telegram no qual você está tentando fazer o login.\n\nNão informe esse código para ninguém. - Seu nome + Seu Nome Digite seu nome e coloque uma foto de perfil. Nome (obrigatório) Sobrenome (opcional) @@ -165,6 +165,7 @@ Fixar Desafixar Arquivar + Arquivo Desarquivar Chats Arquivados Apagar chat @@ -181,7 +182,7 @@ Silenciar por %1$s Restaurar Som Em %1$s - Silenciar para sempre + Desativar HASHTAGS Recente Pessoas @@ -295,7 +296,7 @@ Os usuários removidos do canal pelos admins não podem entrar novamente usando links de convite. Novo Canal Nome do canal - Adicionar contatos no canal + Adicionar pessoas ao canal Se você definir um link permanente, outras pessoas poderão encontrar e participar do seu canal.\n\nVocê pode usar a-z, 0-9 e underline.\nO tamanho mínimo é de 5 caracteres. Se você definir um link permanente, outras pessoas poderão encontrar e participar do seu grupo.\n\nVocê pode usar a-z, 0-9 e underline.\nO tamanho mínimo é de 5 caracteres. Atenção @@ -371,20 +372,20 @@ Vídeo do canal alterado Foto do canal removida Nome do canal alterado para un2 - Desculpe, você reservou muitos nomes públicos. Você pode remover o link público de um dos seus grupos ou canais, ou criar de forma privada. + Você reservou muitos links públicos. Experimente remover o link público de um dos seus grupos ou canais antigos, ou criar de forma privada. Dono - Administrador + Admin Admin SILENCIAR RESTAURAR SOM Adicionar Admin Remover Usuário Desbanir - Toque e segure no usuário para desbanir + Toque e segure no usuário para remover o banimento. Convidar via Link Dispensar admin Editar permissões - Somente os administradores do canal podem ver esta lista. + Somente admins do canal podem ver esta lista. Qualquer pessoa que tenha o Telegram instalado poderá participar do seu canal seguindo esse link. Você pode adicionar administradores para ajudar você a gerenciar o seu canal. Aperte e segure para removê-los. Deseja entrar no canal \'%1$s\'? @@ -397,7 +398,7 @@ Desculpe, você não pode adicionar esse usuário em canais. Desculpe, há muitos administradores neste canal. Desculpe, há bots demais neste canal. - Desculpe, você só pode adicionar os primeiros 200 membros ao canal. Note que um número ilimitado de pessoas podem entrar via link do canal. + Desculpe, você só pode adicionar os primeiros 200 inscritos ao canal. Note que um número ilimitado de pessoas podem entrar via link do canal. Muitos grupos e canais Desculpe, você faz parte de muitos grupos e canais. Por favor, saia de alguns antes de criar outro. Desculpe, você faz parte de muitos grupos e canais. Por favor, saia de alguns antes de entrar em outro. @@ -444,7 +445,7 @@ Apagar Mensagens de Outros Apagar Mensagens Adicionar Novos Admins - Enviar Anonimamente + Permanecer Anônimo Dispensar admin Transferir Posse do Grupo Transferir Posse do Canal @@ -475,7 +476,7 @@ Enviar Mensagens Enviar Mídias Enviar Enquetes - Enviar Stickers & GIFs + Enviar Stickers e GIFs Prévia de Links Mudar Info do Chat Fixar Mensagens @@ -531,7 +532,7 @@ Buscar na Internet Estatísticas Bots só podem ser adicionados como admins. - Desculpe, bots só podem ser adicionados a canais como admins. + Bots só podem ser adicionados aos canais como admins. TORNAR ADMIN %1$s será removido dos admins se você restringir. Conversa @@ -541,7 +542,7 @@ Selecione um grupo para armazenar os comentários do seu canal. Tudo que você postar no canal será encaminhado para este grupo. **%1$s** foi selecionado como o grupo usado para armazenar os comentários do seu canal. - O canal **%1$s** está vinculado a este grupo de conversa. + Este grupo está vinculado como o grupo de conversa para %1$s. Todas as novas mensagens postadas neste canal serão encaminhadas ao grupo. Criar Grupo Desvincular Grupo @@ -567,6 +568,7 @@ O Modo Lento está ativado. Você não pode selecionar mais itens. Desculpe, este texto é muito longo para ser enviado em uma só mensagem.\n\nO Modo Lento está ativado. Você não pode enviar mais de uma mensagem por vez. **%1$s** promovido a admin + **%1$s** removido de **%2$s** Nova Enquete Novo Quiz @@ -639,14 +641,14 @@ Ações Recentes Todas as ações - Ações selecionadas + ações selecionadas Todos os admins **Nenhuma ação ainda**\n\nOs membros e admins do grupo\nainda não tomaram nenhuma ação\nnas últimas 48 horas. **Nenhuma ação ainda**\n\nOs membros e admins do canal\nainda não tomaram nenhuma ação\nnas últimas 48 horas. **Nenhuma ação encontrada**\n\nNenhuma ação recente corresponde à sua busca. Nenhuma ação recente que contenha \"**%1$s**\" foi encontrada. O que são as Ações Recentes? - Essa é uma lista de todas as ações de serviço tomadas pelos membros e admins do grupo nas últimas 48 horas. + Essa é uma lista das ações de serviço notáveis tomadas pelos membros e admins do grupo nas últimas 48 horas. Essa é uma lista de todas as ações de serviço tomadas pelos admins do canal nas últimas 48 horas. un1 renomeou o grupo para \"%1$s\" un1 renomeou o canal para \"%1$s\" @@ -711,13 +713,14 @@ Ler Mensagens alterou os privilégios de %1$s Alterar Info. do Canal - Alterar Info. do grupo + Editar Info. do grupo Postar mensagens Editar mensagens Apagar mensagens Adicionar admins - Enviar anonimamente + Permanecer Anônimo Banir usuários + Gerenciar chats de voz Adicionar usuários Título: %1$s Título @@ -732,8 +735,15 @@ Mensagens editadas Mensagens fixadas Pessoas que saíram + Chats de voz un1 definiu o timer do modo lento para %1$s un1 desativou o modo lento + un1 iniciou um chat de voz + un1 encerrou o chat de voz + un1 silenciou un2 no chat de voz + un1 tirou o silêncio de un2 no chat de voz + un1 permitiu que novos participantes do chat de voz falem + un1 silenciou novos participantes do chat de voz Nova Lista de Transmissão Digite o nome da lista @@ -749,7 +759,7 @@ Música Artista desconhecido Título desconhecido - Repetir música + Repetir faixa Repetir lista Misturar lista Ordem reversa @@ -770,7 +780,7 @@ Arquivos recentes Arquivos A-Z Nenhum resultado - Nada que corresponda com ** %1$s** na pasta de arquivos atual. + Nada que corresponda com **%1$s** na pasta de arquivos atual. Esta pasta está vazia. Para enviar imagens sem compressão Para enviar músicas @@ -852,7 +862,7 @@ DESLIZE PARA CANCELAR Salvar em downloads Salvar em GIFs - Apagar GIF? + Apagar GIF desta seção? Salvar em músicas Compartilhar Aplicar arquivo de localização @@ -904,7 +914,7 @@ Fixar mensagem Desafixar mensagem Deseja fixar uma mensagem mais antiga enquanto deixa a mais recente fixada? - Deseja fixar a mensagem para todos os membros do grupo? + Fixar a mensagem no grupo? Deseja fixar essa mensagem no canal? Deseja fixar essa mensagem no topo do chat? Deseja desafixar essa mensagem? @@ -929,12 +939,19 @@ Outro Descrição Mensagem fixada - Mensagem Anterior + Mensagem anterior Enquete fixada editada Editar Mensagem Editar Legenda Toque para editar a mídia + Editar a foto + Editar o vídeo + Trocar foto + Trocar vídeo + Trocar mídia + Trocar arquivo + Substituir arquivo de áudio Desça para ver os bots %1$s Desculpe, o tempo para editar expirou. @@ -963,7 +980,7 @@ Segure para gravar áudio. Toque para vídeo. Segure para gravar vídeo. Toque para áudio. Descartar Mensagem de Voz - Tem certeza de que deseja parar de gravar e descartar sua mensagem de voz? + Deseja mesmo parar de gravar e descartar a sua mensagem de voz? Descartar Mensagem de Vídeo Tem certeza de que deseja parar de gravar e descartar sua mensagem de vídeo? Descartar @@ -1003,6 +1020,8 @@ Toque para foto, segure para vídeo Toque para ver em lista. Enviar sem som + Enviar como nova foto + Trocar foto Enviar Agora Reagendar Hoje @@ -1116,7 +1135,7 @@ %1$s enviou um arquivo para o grupo %2$s %1$s enviou um GIF para o grupo %2$s %1$s enviou um recibo ao grupo %2$s por %3$s - %1$s enviou uma mensagem de voz para o grupo %2$s + %1$s enviou uma mensagem de voz para %2$s %1$s enviou uma mensagem de vídeo para o grupo %2$s %1$s enviou um arquivo de áudio ao grupo %2$s %1$s enviou um sticker ao grupo %2$s @@ -1126,13 +1145,17 @@ %1$s alterou a foto do grupo para %2$s %1$s alterou o vídeo do grupo para %2$s %1$s convidou %3$s para o grupo %2$s + %1$s convidou %3$s para um chat de voz em %2$s + %1$s convidou você para um chat de voz em %2$s + %1$s iniciou um chat de voz em %2$s + %1$s encerrou um chat de voz em %2$s %1$s retornou ao grupo %2$s %1$s entrou no grupo %2$s %1$s removeu %3$s do grupo %2$s %1$s removeu você do grupo %2$s %1$s saiu do grupo %2$s %1$s entrou para o Telegram! - %1$s,\nDetectamos que alguém acessou a sua conta a partir de um novo dispositivo em %2$s\n\nDispositivo: %3$s\nLocalização: %4$s\n\nSe não foi você, vá em Configurações > Privacidade e Segurança > Sessões Ativas, e termine essa sessão.\n\nSe você acha que alguém acessou a sua conta sem a sua permissão, você pode habilitar a Verificação em Duas Etapas nas configurações de Privacidade e Segurança.\n\nAtenciosamente,\nEquipe do Telegram. + %1$s,\nDetectamos que alguém acessou a sua conta a partir de um novo dispositivo em %2$s\n\nDispositivo: %3$s\nLocalização: %4$s\n\nSe não foi você, vá em Configurações > Dispositivos e termine essa sessão.\n\nSe você acha que alguém acessou a sua conta sem a sua permissão, você pode habilitar a Verificação em Duas Etapas nas configurações de Privacidade e Segurança.\n\nAtenciosamente,\nEquipe do Telegram. %1$s atualizou a foto do perfil %1$s entrou para o grupo %2$s via link de convite %1$s enviou %3$s ao grupo %2$s @@ -1158,7 +1181,7 @@ %1$s fixou um arquivo no grupo %2$s %1$s fixou um sticker no grupo %2$s %1$s fixou um %3$s sticker no grupo %2$s - %1$s fixou uma mensagem de voz no grupo %2$s + %1$s fixou uma mensagem de voz em %2$s %1$s fixou uma mensagem de vídeo no grupo %2$s %1$s fixou um contato %3$s no grupo %2$s %1$s fixou um mapa no grupo %2$s @@ -1245,7 +1268,7 @@ Encontre pessoas próximas Busque pessoas por nome de usuário Novo contato - O número de **%1$s** não está nos seus contatos. Deseja adicionar? + O número de telefone **%1$s** não está nos seus contatos. Deseja adicionar? Adicionar contato Adicionar pessoas... @@ -1262,12 +1285,13 @@ ENTRAR Link copiado. Link copiado.\nEle só funciona para membros deste chat. + This link will only work for members of this chat. Desculpe, você não faz parte da conversa em que essa mensagem foi postada e infelizmente não pode acessá-la. Telefone copiado. Email copiado. Convidar para o Grupo via Link Link de Convite - Tem certeza de que deseja desativar o link de convite? Se fizer isso, ninguém conseguirá usá-lo. + Deseja mesmo desativar o link de convite? Se fizer isso, ninguém conseguirá usá-lo. O link de convite anterior foi desativado. Um novo link foi gerado. Desativar Revogar Link @@ -1284,7 +1308,7 @@ Configurações Adicionar Inscrito Adicionar Membro - Definir administradores + Adicionar admins BANIR DO GRUPO Apagar e sair do grupo Apagar e Sair do Grupo @@ -1296,7 +1320,7 @@ Converter em supergrupo Atenção Essa ação é irreversível. Não é possível voltar de um supergrupo para um grupo normal. - **Limite de membros atingido.**\n\nPara ir além do limite e ter funções adicionais, converta em supergrupo:\n\n• Supergrupos podem ter até %1$s\n• Novos membros podem ver todo o histórico do chat\n• Mensagens apagadas somem para todos os membros\n• Admins podem adicionar uma descrição no grupo\n• O criador pode definir um link público para o grupo + **Limite de membros atingido.**\n\nPara mais espaço e funções adicionais, converta em supergrupo:\n\n• Supergrupos podem ter até %1$s\n• Novos membros podem ver todo o histórico do chat\n• Mensagens apagadas somem para todos os membros\n• Admins podem adicionar uma descrição no grupo\n• O criador pode definir um link público para o grupo **Em supergrupos:**\n\n• Novos membros podem ver todo o histórico do chat\n• Mensagens apagadas somem para todos os membros\n• Admins podem adicionar uma descrição no grupo\n• O criador pode definir um link público para o grupo **Nota:** essa ação não pode ser desfeita. @@ -1307,7 +1331,7 @@ %1$s ainda não está no Telegram. Gostaria de fazer um convite? Convidar BLOQUEAR - BLOQUEAR E APAGAR RESPOSTAS + SIM E APAGAR RESPOSTAS Bloquear usuário Bloquear usuário Bloquear @@ -1366,8 +1390,8 @@ Desculpe, esse usuário é inválido. O nome de usuário deve ter pelo menos 5 caracteres. O nome de usuário não pode exceder 32 caracteres. - Desculpe, o nome de usuário não pode começar com um número. - Você pode escolher um nome de usuário no **Telegram**. Assim, outras pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar saber seu número de telefone.\n\nVocê pode usar **a–z**, **0–9** e underline.\nO tamanho mínimo é de **5** caracteres. + Nomes de usuário não podem começar com um número. + Você pode escolher um nome de usuário no **Telegram**. Se escolher, as pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar do seu número de telefone.\n\nVocê pode usar **a–z**, **0–9** e underline.\nO tamanho mínimo é de **5** caracteres. Este link abre um chat com você:\n%1$s Verificando nome de usuário... %1$s está disponível. @@ -1377,7 +1401,7 @@ Stickers e Máscaras Stickers Animados em Loop Stickers animados serão reproduzidos em chats de forma contínua. - Stickers Animados + Stickers animados Adicionar Stickers ADICIONAR %1$s REMOVER %1$s @@ -1392,7 +1416,7 @@ Stickers do Grupo Mais Stickers Apagar dos Favoritos - Apagar dos Recentes + Remover dos Recentes Adicionar Máscaras Stickers não encontrados Stickers removidos @@ -1435,7 +1459,7 @@ Máscaras Arquivadas Nenhum sticker arquivado Nenhuma máscara arquivada - Você pode ter até 200 pacotes de sticker. Pacotes não usados são arquivados quando você adiciona mais. + Você pode ter 200 pacotes de sticker. Pacotes não usados são arquivados quando você adiciona mais. Você pode ter até 200 pacotes de máscaras. Pacotes não usados são arquivados quando você adiciona mais. ENVIAR STICKER Stickers arquivados @@ -1814,6 +1838,10 @@ Sons no Chat Padrão Padrão + Padrão + Padrão no App + %1$s No App + Silenciosas Notificações Inteligentes Exceções Adicionar Exceção @@ -1960,9 +1988,9 @@ Calculando... Documentos Fotos - Mensagens de vídeo/voz + Mensagens voz e vídeo Vídeos - Música + Músicas GIFs Outros arquivos Vazio @@ -2030,7 +2058,7 @@ Digite o código de confirmação que acabamos de enviar para %1$s. Por favor, digite sua senha para acessar seus dados pessoais. %1$s solicita acesso aos seus dados pessoais para que você assine os serviços deles. - Por favor, digite a senha do Telegram para descriptografar seus dados. + Digite a senha do Telegram para descriptografar seus dados. Você aceita a *Política de Privacidade de %1$s* e permite que @%2$s te envie mensagens. Você está enviando seus documentos diretamente para %1$s e permitindo que %2$s envie mensagens para você. AUTORIZAR @@ -2160,7 +2188,7 @@ Vietnamita Sessões Ativas - Sessão atual + Este dispositivo Nenhuma outra sessão ativa Você pode entrar no Telegram em outros celulares, tablets e computadores usando o mesmo número de telefone. Todos os seus dados serão sincronizados. Sessões ativas @@ -2230,7 +2258,7 @@ Bots Adicionando chats Aguarde um momento enquanto preenchemos esta pasta para você... - Nenhum chat encontrado + Pasta vazia Não há nenhum chat nesta\npasta no momento. Nova Pasta Sem Chats @@ -2312,11 +2340,11 @@ novembro dezembro Arquivos - Mídia + Mídias Mídia Compartilhada Grupos Links - Música + Músicas Voz GIFs Arquivos Compartilhados @@ -2355,7 +2383,7 @@ Direções Nenhum lugar encontrado. Não há nada relacionado com **%1$s** perto de você. - Enviar minha localização atual + Enviar Minha Localização Atual Compartilhar em Tempo Real... Enviar Localização em Tempo Real Parar Compartilhamento @@ -2422,7 +2450,7 @@ Alertar quando outros participantes estiverem perto Alerta de proximidade ativado Vamos te notificar quando %1$s estiver a %2$s de você. - We will notify you once someone is within %1$s from you. + Vamos te notificar quando alguém estiver a %1$s de você. Alerta de proximidade cancelado Exibir em lista @@ -2574,6 +2602,7 @@ Voltar às Configurações Voltar ao Passport Configurar Senha + Show password Configurar senha adicional Você pode configurar uma senha que será solicitada quando você entrar em um novo dispositivo, após o código SMS. Sua senha @@ -2630,7 +2659,7 @@ Código de recuperação O código de recuperação foi enviado para o email fornecido:\n\n%1$s Por favor, verifique o seu email e digite o código de 6 dígitos que te enviamos. - Está tendo problemas para acessar seu email %1$s? + Problemas ao acessar %1$s? Problemas ao acessar o seu email? Se você não puder acessar o seu email, as suas únicas opções são lembrar a senha ou apagar a sua conta. APAGAR MINHA CONTA @@ -2641,7 +2670,7 @@ Senha Você ativou a Verificação em Duas Etapas e a sua conta está protegida com uma senha adicional. Esqueceu a senha? - Recuperação de senha + Recuperação de Senha Código Senha desativada Reenviar código @@ -2654,6 +2683,7 @@ Uso de disco e de rede Uso do Armazenamento Uso de Dados + Caminho de Armazenamento Móvel Wi-Fi Roaming @@ -2676,8 +2706,8 @@ Privacidade e Segurança Privacidade Último Acesso e Online - Foto de Perfil - Quem pode ver minha foto de perfil? + Fotos de Perfil + Quem pode ver minhas fotos e vídeos de perfil? Você pode restringir quem pode ver sua foto de perfil com precisão granular. Você pode adicionar usuários ou grupos inteiros como exceções que substituirão as configurações acima. Número de Telefone @@ -2734,7 +2764,7 @@ Quem pode ver o seu Último Acesso? Definir exceções Adicionar às exceções - Você não poderá ver o Último Acesso e status online das pessoas com quem você não compartilha o seu. Em vez disso, você verá o último acesso aproximado (recentemente; há uma semana; há um mês). + Você não poderá ver o Último Acesso ou status online das pessoas com quem você não compartilha o seu. Em vez disso, você verá horários aproximados (recentemente; há uma semana; há um mês). Você alterou algumas configurações de privacidade. Gostaria de aplicar? Sempre Mostrar Para Nunca Mostrar Para @@ -2852,6 +2882,14 @@ un1 está a %1$s de você Você está a %1$s de un1 un1 está agora a %1$s de un2 + un1 convidou você para este grupo + un1 convidou você para este canal + un1 iniciou um chat de voz + Você iniciou um chat de voz + Chat de voz encerrado (%s) + un1 convidou un2 para o chat de voz + Você convidou un2 para o chat de voz + un1 convidou você para o chat de voz Você permitiu que o bot te envie mensagens ao fazer o login em %1$s. %1$s recebeu os seguintes documentos: %2$s Dados pessoais @@ -2910,7 +2948,7 @@ Código expirado. Por favor, tente entrar novamente. Muitas tentativas. Por favor, tente depois. Muitas tentativas. Por favor, tente novamente em %1$s. - Código inválido + Código inválido. Por favor, tente de novo. Desculpe, você apagou e recriou a sua conta muitas vezes recentemente. Aguarde alguns dias antes de tentar novamente. Nome inválido Desculpe, este sobrenome não pode ser usado @@ -2991,7 +3029,7 @@ Deseja enviar esse contato para **%1$s**? Não existe conta no Telegram com esse nome de usuário. Esse bot não pode entrar em grupos. - Deseja ativar a prévia de links estendida em Chats Secretos? Note que a pré-visualização é gerada nos servidores do Telegram. + Ativar a prévia estendida de links em Chats Secretos? Note que a prévia é gerada nos servidores do Telegram. Os bots inline são fornecidos por desenvolvedores terceiros. Para o bot funcionar, os símbolos que você digita depois do nome de usuário do bot são enviados para o respectivo desenvolvedor. Desculpe, você não pode editar essa mensagem. Permita o acesso às ligações ao Telegram, assim podemos automaticamente adicionar o código para você. @@ -3020,15 +3058,18 @@ Para que você se conecte aos seus amigos em todos os dispositivos, seus contatos serão sincronizados continuamente com os servidores fortemente criptografados do Telegram. O Telegram precisa de acesso ao armazenamento para que você possa enviar e salvar fotos, vídeos, músicas e outras mídias. - Telegram precisa acessar seu microfone para que você possa enviar mensagens de voz. + O Telegram precisa de acesso ao microfone para que você possa enviar mensagens de voz. Telegram precisa acessar seu microfone para que você possa gravar vídeos. O Telegram precisa de acesso à câmera para que você possa tirar fotos e vídeos. Por favor, ative a permissão nas Configurações. Telegram precisa acessar sua localização para que você possa compartilhar com seus amigos. O Telegram precisa acessar sua localização Para reproduzir vídeos no modo PiP, o Telegram precisa de acesso para aparecer sobre outros apps. + O modo flutuante permite usar o recurso \"Aperte para Falar\" e também ver quem está falando até mesmo quando você estiver fora do Telegram. CONFIGURAÇÕES Por favor, permita que o Telegram seja mostrado na tela de bloqueio para que as chamadas possam funcionar corretamente. Para enviar a sua localização em tempo real neste chat, o Telegram precisa de acesso contínuo à sua localização, inclusive enquanto o app estiver em segundo plano.\n\nO Telegram acessará a sua localização somente pela duração que você escolher e você pode parar de compartilhar a qualquer momento. Não usaremos a sua localização para nenhum outro motivo além de compartilhar neste chat. + Picture-in-Picture + Chat de voz flutuante Crescimento Inscritos @@ -3105,8 +3146,8 @@ Hoje Ontem Visualizações - Compartilhamentos Públicos - Compartilhamentos Privados + Compartil. Públicos + Compartil. Privados Ver Estatísticas Ver Estatísticas do Canal Estatísticas da Mensagem @@ -3122,7 +3163,7 @@ O **Telegram** envia mensagens mais rápido que qualquer outro aplicativo. O **Telegram** será grátis para sempre.\nSem anúncios. Sem tarifas. O **Telegram** mantém suas mensagens\nseguras contra ataques de hackers. - O **Telegram** não tem limites no tamanho de suas mídias e chats. + O **Telegram** não tem limites no tamanho das suas mídias e chats. O **Telegram** permite que você acesse suas mensagens\nem vários dispositivos. Comece a Conversar @@ -3141,9 +3182,14 @@ Chamada via Telegram Videochamada via Telegram Chamada via Telegram em andamento + Chat de Voz Acontecendo Encerrar Outra chamada em andamento - Você está em uma chamada com **%1$s**. Gostaria de desligar e iniciar uma nova com **%2$s**? + Encerrar chamada com **%1$s** e começar outra com **%2$s**? + Encerrar a chamada com **%1$s** e iniciar um chat de voz em **%2$s**? + Outro chat de voz acontecendo + Sair do chat de voz em **%1$s** e começar outro em **%2$s**? + Sair do chat de voz em **%1$s** e ligar para **%2$s**? Chamadas Toque Você pode personalizar o toque usado quando esse contato te ligar no Telegram. @@ -3160,7 +3206,9 @@ Atender Rejeitar Você está offline. Por favor, conecte-se à Internet para poder realizar chamadas. + Você está offline no momento. Por favor, conecte-se à Internet para participar de chats de voz. Você está com o modo avião ativado. Desative-o ou conecte-se ao Wi-Fi para realizar chamadas. + O modo avião está ativado. Por favor, desative o modo ou conecte-se à rede Wi-Fi para participar de chats de voz. Desconectado Modo Avião Configurações @@ -3175,7 +3223,7 @@ Videochamada cancelada Videochamada recusada %1$s (%2$s) - Você ainda não realizou chamadas. + Ainda sem chamadas aqui... O aplicativo de **%1$s** está usando um protocolo incompatível. O aplicativo desse usuário precisa ser atualizado para que você possa chamá-lo. O aplicativo de **%1$s** não faz chamadas e precisa ser atualizado para isso. Desculpe, a versão do Telegram de **%1$s** é antiga e não faz videochamadas. @@ -3192,10 +3240,10 @@ Videochamada via Telegram Auricular Headset - Alto-falante + Viva-voz Bluetooth Dispositivos de Saída - RETORNAR À LIGAÇÃO + VOLTAR À CHAMADA Desculpe, você não pode realizar essa chamada por conta das configurações de privacidade de %1$s. Se os emojis na tela de %1$s são os mesmos, esta chamada é 100%% segura. Avaliar Chamada @@ -3205,7 +3253,7 @@ Agradecemos por ajudar a tornar as chamadas do Telegram melhores. respondendo como %s Responder com Texto - Essas respostas rápidas estarão disponíveis quando você responder a uma ligação com uma mensagem. Altere-as para dizer o que você quiser. + Essas respostas rápidas estarão disponíveis quando você responder a uma chamada com uma mensagem. Altere-as para dizer o que você quiser. Não posso falar agora, está tudo certo? Já te ligo de volta Vou te ligar mais tarde @@ -3226,10 +3274,15 @@ Vídeo quadriculado Toque aqui para ligar a sua câmera Ativar Som + ou segure e fale + Você está Ao Vivo + Silenciado por admin + Silenciado + Você está no Modo Ouvinte Silenciar Iniciar Vídeo Parar Vídeo - Alto-falante + Viva-voz Virar Alternar para videochamada? ALTERNAR @@ -3244,6 +3297,61 @@ Fazer videochamada para **%1$s**? Videochamada Reconectando + Iniciar Chat de Voz + Chat de Voz + Iniciar um chat de voz neste grupo? + Gerenciar Chats de Voz + Entrar + %1$s pessoas conversando + %1$s pessoa falando + %1$s pessoas conversando + %1$s pessoas conversando + %1$s pessoas conversando + %1$s pessoas conversando + falando + escutando + convidado + Sair + Encerrar + Silenciar microfone + Deseja mesmo silenciar **%1$s** neste chat de voz? + Remover membro + Deseja remover %1$s do grupo? + **%1$s** foi removido do grupo. + **%1$s** agora pode falar. + **%1$s** está silenciado neste chat. + Silenciar + Novos membros podem falar + Silenciar novos membros + Convidar via link + Encerrar chat de voz + Conectando... + Sair do chat de voz + Deseja mesmo sair deste chat de voz? + Encerrar chat de voz + Deseja mesmo encerrar este chat de voz? + Encerrar chat de voz + VER CHAT DE VOZ + Chat de Voz + Abrir chat de voz + O usuário selecionado já está no chat de voz. + Desculpe, admins anônimos não podem participar de chats de voz. + un1 convidou un2 para o chat de voz + Entrar no chat de voz + Olá! Junte-se ao nosso chat de voz: %1$s + Convidar Membros + Remover + Permitir falar + Buscar membros para convidar... + Copiar Link de Convite + O link de convite foi copiado. + Ativar Som + Chat de voz encerrado. Começar um novo? + Adicionar Membro + Deseja adicionar **%1$s** a **%2$s**? + Você convidou **%1$s** para o chat de voz. + Adicionar + Toque para entrar Mensagem para %1$s Chamar %1$s por voz @@ -3327,6 +3435,12 @@ %1$d membros %1$d membros %1$d membros + %1$d participantes + %1$d participante + %1$d participantes + %1$d participantes + %1$d participantes + %1$d participantes e mais %1$d escrevendo e mais %1$d escrevendo e mais %1$d escrevendo @@ -3346,7 +3460,7 @@ %1$d novas mensagens %1$d novas mensagens %1$d mensagens desafixadas - mensagem desafixada + Mensagem desafixada %1$d mensagens desafixadas %1$d mensagens desafixadas %1$d mensagens desafixadas @@ -3751,6 +3865,9 @@ Agendado para %s Voltar Abrir menu de navegação + Abrir menu + Fechar menu + Open in photo viewer %2$s por %1$s Mais opções Reproduzir @@ -3898,4 +4015,5 @@ \'Lembrar hoje às\' HH:mm \'Lembrar em\' d \'de\' MMM \'às\' HH:mm \'Lembrar em\' d \'de\' MMM \'de\' yyyy \'às\' HH:mm + Ativar diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index d5c59cd786f..b02bc715898 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -2602,6 +2602,7 @@ Return to Settings Return to Passport Set Password + Show password Set Additional Password You can set a password that will be required when you log in on a new device in addition to the code you get in the SMS. Your Password @@ -3866,6 +3867,7 @@ Open navigation menu Open menu Close menu + Open in photo viewer %2$s by %1$s More options Play