Compare commits

...

74 Commits
v4.9.2 ... main

Author SHA1 Message Date
xmflsct 7bcef6fe1d
Fix patch 2024-02-07 00:26:41 +01:00
xmflsct 6f27785a12
Try fixing navigation 2024-02-07 00:22:22 +01:00
xmflsct 5cec5e8084
Clean up 2024-02-06 22:09:36 +01:00
xmflsct 7b63150e73
Squashed commit of the following:
commit 37d93d723606fc3b43ec3e0379e0a87b27afac72
Author: xmflsct <me@xmflsct.com>
Date:   Mon Feb 5 01:14:40 2024 +0100

    Match Android

commit 3a192afc7704fcab7ddd14c5496ad68eac12405c
Author: xmflsct <me@xmflsct.com>
Date:   Mon Feb 5 00:33:38 2024 +0100

    Updates

commit 84617bdadf7fd0ba6474e610a174decc92015b0b
Author: xmflsct <me@xmflsct.com>
Date:   Mon Feb 5 00:24:56 2024 +0100

    Updates

commit 9919e8890e02e7d583046e22e3dbe34af02e3f28
Author: xmflsct <me@xmflsct.com>
Date:   Mon Feb 5 00:19:19 2024 +0100

    Updates

commit fca65a03665f4162696dc50c16098bc28f336f31
Author: xmflsct <me@xmflsct.com>
Date:   Mon Feb 5 00:13:20 2024 +0100

    Updates

commit d208d67a052464939197a15877f67302f262c222
Author: xmflsct <me@xmflsct.com>
Date:   Mon Feb 5 00:09:05 2024 +0100

    Updates

commit 5527ebca78d863515848521571657f1eac628de4
Author: xmflsct <me@xmflsct.com>
Date:   Mon Feb 5 00:03:19 2024 +0100

    Bump core
2024-02-05 01:14:54 +01:00
xmflsct 997a267b89
Update Gemfile.lock 2024-02-04 12:51:44 +01:00
xmflsct 41c09d4ae9
Bump building chain 2024-02-04 12:39:10 +01:00
xmflsct a70dce9780
New Crowdin updates (#762)
* New translations tabs.json (Swedish)

* New translations instance.json (Portuguese, Brazilian)

* New translations timeline.json (Portuguese, Brazilian)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations tabs.json (Swedish)

* New translations common.json (Russian)

* New translations instance.json (Russian)

* New translations parse.json (Russian)

* New translations relationship.json (Russian)

* New translations timeline.json (Russian)

* New translations timeline.json (Russian)
2023-11-12 17:57:10 +01:00
xmflsct d16178abc9
Bump patch versions 2023-11-12 17:44:52 +01:00
xmflsct fa8d7ed47e
New Crowdin updates (#760)
* New translations tabs.json (Portuguese, Brazilian)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations tabs.json (Portuguese, Brazilian)
2023-08-28 00:40:30 +02:00
xmflsct 9f8064ded4
Fix Android crashes using PlatformColor 2023-08-28 00:27:10 +02:00
vitalyster c3aba848a5
Use system separator color in Separator component (#757)
* border color is too distracting and does not look "native". Now we using system separator color to provide "native" experience :-)
2023-08-24 22:21:31 +02:00
xmflsct f64135a6df
Fix #756 2023-08-22 00:03:06 +02:00
xmflsct 1de8a40cda
New Crowdin updates (#752)
* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Dutch)

* New translations tabs.json (Dutch)

* New translations common.json (Portuguese, Brazilian)

* New translations parse.json (Portuguese, Brazilian)

* New translations timeline.json (Portuguese, Brazilian)

* New translations tabs.json (Portuguese, Brazilian)

* New translations tabs.json (Swedish)

* New translations tabs.json (Swedish)

* New translations common.json (Swedish)

* New translations contextMenu.json (Swedish)
2023-08-17 10:07:44 +02:00
xmflsct c5c616e3dc
Fix #754 2023-08-16 23:47:00 +02:00
xmflsct 34043fc1b3
Bumps 2023-07-30 21:45:08 +02:00
xmflsct 5b031b40c0
New Crowdin updates (#751)
* New translations tabs.json (German)

* New translations tabs.json (Chinese Traditional)
2023-07-16 23:10:14 +02:00
xmflsct 7b6c9d5130
Update index.tsx 2023-07-16 23:10:05 +02:00
xmflsct da623dac56
New Crowdin updates (#748)
* New translations tabs.json (Belarusian)

* New translations tabs.json (French)

* New translations tabs.json (Spanish)

* New translations tabs.json (Catalan)

* New translations tabs.json (Czech)

* New translations tabs.json (German)

* New translations tabs.json (Greek)

* New translations tabs.json (Basque)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* New translations tabs.json (Dutch)

* New translations tabs.json (Norwegian)

* New translations tabs.json (Polish)

* New translations tabs.json (Russian)

* New translations tabs.json (Swedish)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Chinese Simplified)

* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Vietnamese)

* New translations tabs.json (Portuguese, Brazilian)

* New translations tabs.json (Spanish)

* New translations tabs.json (Catalan)

* New translations tabs.json (Basque)

* New translations tabs.json (Norwegian)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (German)

* New translations tabs.json (Dutch)

* New translations tabs.json (Chinese Simplified)

* New translations tabs.json (Chinese Traditional)
2023-07-14 23:08:10 +02:00
xmflsct 0a99669af6
Update index.tsx 2023-07-14 22:56:08 +02:00
xmflsct cdd80250d1
Fix muting 2023-07-14 21:48:12 +02:00
xmflsct 09bc6c30af
Added a button to fetch latest toot on load 2023-07-13 23:30:26 +02:00
xmflsct 8b3ca21ac9
Fix #749 2023-07-13 22:26:06 +02:00
xmflsct 6e5b06f3a7
Fix #734 2023-07-13 21:55:26 +02:00
xmflsct f7729f33db
Fix Android menu indication 2023-07-12 23:36:44 +02:00
xmflsct f2b275d815
Bumps 2023-07-12 22:34:50 +02:00
xmflsct 0e64350df8
New Crowdin updates (#745)
* New translations tabs.json (Belarusian)

* New translations common.json (Italian)

* New translations instance.json (Italian)

* New translations timeline.json (Italian)
2023-07-11 23:31:30 +02:00
xmflsct 760c8b4c68
Bump packages 2023-07-11 23:21:41 +02:00
xmflsct f1ba7ce377
Test iOS
Known Android build failure
2023-06-22 00:07:17 +02:00
xmflsct 3154540bba
Bump packages 2023-06-21 23:05:40 +02:00
xmflsct 93b3ac1618
Bump JS packages 2023-06-09 23:56:15 +02:00
xmflsct 4b2b701cea
Fix #741 2023-06-09 23:50:36 +02:00
dependabot[bot] 33709f8fa6
Bump fast-xml-parser from 4.2.2 to 4.2.4 (#742)
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) from 4.2.2 to 4.2.4.
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/commits)

---
updated-dependencies:
- dependency-name: fast-xml-parser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-09 23:18:15 +02:00
xmflsct 1375bc95cd
Fix version check 2023-05-20 22:47:58 +02:00
xmflsct 23a8e5cd19
Bump packages 2023-05-20 22:47:32 +02:00
xmflsct c5eb1591f8
New Crowdin updates (#740)
* New translations relationship.json (Vietnamese)

* New translations contextMenu.json (Vietnamese)
2023-05-17 13:51:22 +02:00
xmflsct 96c219e3f9
Bump zeego 2023-05-17 13:49:16 +02:00
xmflsct a940ed4cf3
Fix visuals and haptics 2023-05-17 13:39:55 +02:00
xmflsct c1e9c738c5
Bump packages 2023-05-16 22:31:41 +02:00
xmflsct 4f9e9e7a14
Show avatar in actioned statement 2023-05-16 22:12:25 +02:00
xmflsct df7eb26057
Update HeaderAndroid.tsx 2023-05-16 22:00:26 +02:00
xmflsct a8243adf51
More permissive logging in 2023-05-16 21:51:03 +02:00
xmflsct 8aeeb1d806
New Crowdin updates (#739)
* New translations timeline.json (Catalan)

* New translations timeline.json (Spanish)

* New translations compose.json (Belarusian)
2023-05-15 22:49:35 +02:00
xmflsct 05958b66f6
Fix #737 2023-05-15 22:30:18 +02:00
xmflsct 141d5916fd
Fix #736 2023-05-15 21:45:00 +02:00
xmflsct ff14f086a7
Try to bump build system 2023-05-15 21:27:23 +02:00
xmflsct 46a30585a7
Bump packages 2023-05-15 21:26:32 +02:00
xmflsct 48e51530b1 Persistant 🪜 setting 2023-04-19 22:34:14 +02:00
xmflsct 63c4ffbabf Bump packages 2023-04-19 22:06:46 +02:00
xmflsct 40274ef28c Add new neodb cards 2023-04-18 22:53:50 +02:00
xmflsct 21200a7758 Delay prepending to make sure it works 2023-04-18 22:29:05 +02:00
xmflsct 5b670f5d13 Fixed why toot page is not interactable 2023-04-18 22:23:39 +02:00
xmflsct 36202028f9
New Crowdin updates (#725)
* New translations timeline.json (Ukrainian)

* New translations timeline.json (Vietnamese)

* New translations tabs.json (Vietnamese)

* New translations timeline.json (Vietnamese)

* New translations tabs.json (Vietnamese)

* New translations common.json (Vietnamese)

* New translations contextMenu.json (Vietnamese)
2023-04-18 00:09:15 +02:00
xmflsct cde5a14cab Bump deps 2023-04-18 00:08:56 +02:00
xmflsct a4152a5bb6 Fix #733 2023-04-17 23:57:23 +02:00
xmflsct 91596a46c4 Fix #732 2023-04-17 23:44:56 +02:00
xmflsct d3f75cfc22 Fix #729 2023-04-17 23:33:40 +02:00
xmflsct 93b53ec158 Add Greek translation 2023-04-17 23:21:00 +02:00
xmflsct 016ea33e26 A bit more tolerant of local search 2023-04-17 23:12:29 +02:00
xmflsct 824730bc40 Reset after failed auto refetch 2023-04-17 23:00:10 +02:00
xmflsct 7a5464e38a Navigate follow push to account page 2023-04-17 22:42:56 +02:00
xmflsct 768a27d37c Also update counts even when no new remote content 2023-04-17 22:32:09 +02:00
xmflsct 6ed54c3f16 Fix spacing between paragraphs 2023-04-17 22:26:59 +02:00
xmflsct 79fc0c814c Added another outdated instance 2023-04-13 22:47:30 +02:00
xmflsct e74a73fbd7 Update counts with remote data 2023-04-12 23:48:39 +02:00
xmflsct 20152790f5 Fix default theming before selecting 2023-04-10 19:15:37 +02:00
xmflsct 0fc68e56d3 Bump up packages 2023-04-10 19:15:26 +02:00
xmflsct 6c1eba0de7
New translations tabs.json (Belarusian) (#724) 2023-03-19 23:36:05 +01:00
xmflsct a1361570a5 Remove context view 2023-03-19 23:35:20 +01:00
xmflsct b308932e74 Fix account page toot not update 2023-03-19 23:26:30 +01:00
xmflsct 521d8f75fc Add simple image viewer pan decay 2023-03-19 23:18:43 +01:00
xmflsct 86e502afdd Refine neodb cards
Added card for games
2023-03-19 22:15:51 +01:00
xmflsct aa469c1174 Block cards that without properly fetched data 2023-03-19 00:15:10 +01:00
xmflsct 0d8fdf5740 Fix #723 2023-03-18 23:18:09 +01:00
xmflsct 0ca2047f89 Fix #717 2023-03-18 23:03:25 +01:00
157 changed files with 10446 additions and 8993 deletions

View File

@ -7,12 +7,12 @@ on:
jobs: jobs:
build-ios: build-ios:
runs-on: macos-12 runs-on: macos-14
steps: steps:
- uses: tj-actions/branch-names@v6 - uses: tj-actions/branch-names@v8
id: branch id: branch
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-node@v3 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- run: corepack enable - run: corepack enable
@ -20,7 +20,7 @@ jobs:
- run: bundle install - run: bundle install
- run: yarn app:build ios - run: yarn app:build ios
env: env:
DEVELOPER_DIR: /Applications/Xcode_14.2.app/Contents/Developer DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
ENVIRONMENT: ${{ steps.branch.outputs.current_branch }} ENVIRONMENT: ${{ steps.branch.outputs.current_branch }}
SENTRY_ENVIRONMENT: ${{ steps.branch.outputs.current_branch }} SENTRY_ENVIRONMENT: ${{ steps.branch.outputs.current_branch }}
LC_ALL: en_US.UTF-8 LC_ALL: en_US.UTF-8
@ -38,18 +38,18 @@ jobs:
GH_PAT_GET_RELEASE: ${{ secrets.GITHUB_TOKEN }} GH_PAT_GET_RELEASE: ${{ secrets.GITHUB_TOKEN }}
build-android: build-android:
runs-on: macos-12 runs-on: macos-14
steps: steps:
- uses: tj-actions/branch-names@v6 - uses: tj-actions/branch-names@v8
id: branch id: branch
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-node@v3 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- uses: actions/setup-java@v3 - uses: actions/setup-java@v4
with: with:
distribution: 'zulu' distribution: 'zulu'
java-version: '11' java-version: '17'
- run: corepack enable - run: corepack enable
- run: yarn install - run: yarn install
- run: bundle install - run: bundle install
@ -67,19 +67,19 @@ jobs:
GH_PAT_GET_RELEASE: ${{ secrets.GITHUB_TOKEN }} GH_PAT_GET_RELEASE: ${{ secrets.GITHUB_TOKEN }}
create-release: create-release:
runs-on: macos-12 runs-on: macos-14
needs: [build-ios, build-android] needs: [build-ios, build-android]
steps: steps:
- uses: tj-actions/branch-names@v6 - uses: tj-actions/branch-names@v8
id: branch id: branch
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-node@v3 - uses: actions/setup-node@v4
with: with:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
- uses: actions/setup-java@v3 - uses: actions/setup-java@v4
with: with:
distribution: 'zulu' distribution: 'zulu'
java-version: '11' java-version: '17'
- run: corepack enable - run: corepack enable
- run: yarn install - run: yarn install
- run: bundle install - run: bundle install

2
.nvmrc
View File

@ -1 +1 @@
18 20

View File

@ -1,13 +0,0 @@
diff --git a/ios/EXAV/EXAudioSessionManager.m b/ios/EXAV/EXAudioSessionManager.m
index 81dce13366c3947b12c863f7b39c0237882a6c36..fa27e0a354d48a994ca46e19642a5e224d42d9a8 100644
--- a/ios/EXAV/EXAudioSessionManager.m
+++ b/ios/EXAV/EXAudioSessionManager.m
@@ -170,7 +170,7 @@ - (void)moduleDidBackground:(id)backgroundingModule
[_foregroundedModules compact];
// Any possible failures are silent
- [self _updateSessionConfiguration];
+ // [self _updateSessionConfiguration];
}
- (void)moduleDidForeground:(id)module

View File

@ -1,14 +0,0 @@
diff --git a/src/functions/Helpers.ts b/src/functions/Helpers.ts
index e04486540494891ab07ec130b686dc4acddf2d0c..265e6ac11439276a1c52c222dfc4c50daf1689ae 100644
--- a/src/functions/Helpers.ts
+++ b/src/functions/Helpers.ts
@@ -77,7 +77,8 @@ export function getNativeNodeHandle(nativeRef: React.Component){
const nodeHandle = findNodeHandle(nativeRef);
if(nodeHandle == null){
- throw new Error('Unable to get the node handle for the native ref.');
+ return 0
+ // throw new Error('Unable to get the node handle for the native ref.');
};
return nodeHandle;

View File

@ -0,0 +1,64 @@
diff --git a/ios/Sources/Common/AutoLayoutWrapperView.swift b/ios/Sources/Common/AutoLayoutWrapperView.swift
index e2b9be9c129c66eed3eaebb4e33f5456ce98f5da..ef6a0087f524c8d228b7fee31e54fc3dba769ffa 100644
--- a/ios/Sources/Common/AutoLayoutWrapperView.swift
+++ b/ios/Sources/Common/AutoLayoutWrapperView.swift
@@ -18,7 +18,11 @@ class AutoLayoutWrapperView: UIView {
override func addSubview(_ view: UIView) {
if let detachedView = view as? RNIDetachedView {
- detachedView.updateBounds(newSize: self.bounds.size);
+ do {
+ try detachedView.updateBounds(newSize: self.bounds.size);
+ } catch {
+ print("Error: \(error)");
+ };
};
super.addSubview(view);
@@ -37,7 +41,11 @@ class AutoLayoutWrapperView: UIView {
func updateSizeOfSubviews(newSize: CGSize? = nil){
self.subviews.forEach {
guard let detachedView = $0 as? RNIDetachedView else { return };
- detachedView.updateBounds(newSize: newSize ?? self.bounds.size);
+ do {
+ try detachedView.updateBounds(newSize: newSize ?? self.bounds.size);
+ } catch {
+ print("Error: \(error)");
+ };
};
};
};
diff --git a/ios/Sources/RNIContextMenuView/RNIContextMenuPreviewController.swift b/ios/Sources/RNIContextMenuView/RNIContextMenuPreviewController.swift
index 2b4dc6287c68c88d6652b963ac2cc5f59251ffa9..7c8472e90dac8359f6b40ce2c096323fcf388249 100644
--- a/ios/Sources/RNIContextMenuView/RNIContextMenuPreviewController.swift
+++ b/ios/Sources/RNIContextMenuView/RNIContextMenuPreviewController.swift
@@ -63,7 +63,11 @@ class RNIContextMenuPreviewController: UIViewController {
case .STRETCH:
guard let menuCustomPreviewView = self.menuCustomPreviewView else { return };
- menuCustomPreviewView.updateBounds(newSize: self.view.bounds.size);
+ do {
+ try menuCustomPreviewView.updateBounds(newSize: self.view.bounds.size);
+ } catch {
+ print("Error: \(error)");
+ };
self.preferredContentSize = .zero;
case .INHERIT:
diff --git a/ios/Sources/RNIContextMenuView/RNIContextMenuView.swift b/ios/Sources/RNIContextMenuView/RNIContextMenuView.swift
index affabcdee8303681f1438c6cfdb9d90d6a105ba6..7c470229e06250f4bd80d3133e381b91ff4f61c5 100644
--- a/ios/Sources/RNIContextMenuView/RNIContextMenuView.swift
+++ b/ios/Sources/RNIContextMenuView/RNIContextMenuView.swift
@@ -307,7 +307,11 @@ public class RNIContextMenuView:
.init(with: detachedView)
);
- detachedView.detach();
+ do {
+ try detachedView.detach();
+ } catch {
+ print("Error: \(error)");
+ };
};
#if DEBUG

View File

@ -0,0 +1,38 @@
diff --git a/src/zoom.tsx b/src/zoom.tsx
index 70ce1c8d6a43e711f06b93d1eda3b44a3ad9a659..cdc2713470f2d332b8bf3e9c97e38fd9b78281df 100644
--- a/src/zoom.tsx
+++ b/src/zoom.tsx
@@ -4,6 +4,7 @@ import Animated, {
useSharedValue,
useAnimatedStyle,
useDerivedValue,
+ withDecay,
withTiming,
cancelAnimation,
runOnJS,
@@ -120,11 +121,22 @@ export function Zoom(props: Props) {
}
}
})
- .onEnd(() => {
+ .onEnd((event) => {
if (isPinching.value || !isZoomed.value) return;
- panTranslateX.value = 0;
- panTranslateY.value = 0;
+ const maxTranslateX = (viewWidth.value / 2) * scale.value - viewWidth.value / 2;
+ const minTranslateX = -maxTranslateX;
+ translationX.value = withDecay({
+ velocity: event.velocityX,
+ clamp: [minTranslateX, maxTranslateX]
+ });
+
+ const maxTranslateY = (viewHeight.value / 2) * scale.value - viewHeight.value / 2;
+ const minTranslateY = -maxTranslateY;
+ translationY.value = withDecay({
+ velocity: event.velocityY,
+ clamp: [minTranslateY, maxTranslateY]
+ });
});
const pinch = Gesture.Pinch()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

893
.yarn/releases/yarn-4.1.0.cjs vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
compressionLevel: mixed
enableGlobalCache: false
nodeLinker: node-modules nodeLinker: node-modules
plugins: yarnPath: .yarn/releases/yarn-4.1.0.cjs
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
spec: "@yarnpkg/plugin-typescript"
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"

View File

@ -1,6 +1,13 @@
source "https://rubygems.org" source "https://rubygems.org"
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby ">= 2.6.10"
# Cocoapods 1.15 introduced a bug which break the build. We will remove the upper
# bound in the template on Cocoapods with next React Native release.
gem 'cocoapods', '>= 1.13', '< 1.15'
gem 'activesupport', '>= 6.1.7.5', '< 7.1.0'
gem "fastlane" gem "fastlane"
gem 'cocoapods'
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path) eval_gemfile(plugins_path) if File.exist?(plugins_path)

View File

@ -8,37 +8,37 @@ GEM
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
minitest (>= 5.1) minitest (>= 5.1)
tzinfo (~> 2.0) tzinfo (~> 2.0)
addressable (2.8.1) addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0) public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5) algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3) httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1) json (>= 1.5.1)
artifactory (3.0.15) artifactory (3.0.15)
atomos (0.1.3) atomos (0.1.3)
aws-eventstream (1.2.0) aws-eventstream (1.3.0)
aws-partitions (1.722.0) aws-partitions (1.887.0)
aws-sdk-core (3.170.0) aws-sdk-core (3.191.0)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0) aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5) aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1) jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.63.0) aws-sdk-kms (1.77.0)
aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-core (~> 3, >= 3.191.0)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.119.1) aws-sdk-s3 (1.143.0)
aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-core (~> 3, >= 3.191.0)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4) aws-sigv4 (~> 1.8)
aws-sigv4 (1.5.2) aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4) babosa (1.0.4)
claide (1.1.0) claide (1.1.0)
cocoapods (1.12.0) cocoapods (1.14.3)
addressable (~> 2.8) addressable (~> 2.8)
claide (>= 1.0.2, < 2.0) claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.12.0) cocoapods-core (= 1.14.3)
cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.6.0, < 2.0) cocoapods-downloader (>= 2.1, < 3.0)
cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.6.0, < 2.0) cocoapods-trunk (>= 1.6.0, < 2.0)
@ -50,8 +50,8 @@ GEM
molinillo (~> 0.8.0) molinillo (~> 0.8.0)
nap (~> 1.0) nap (~> 1.0)
ruby-macho (>= 2.3.0, < 3.0) ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0) xcodeproj (>= 1.23.0, < 2.0)
cocoapods-core (1.12.0) cocoapods-core (1.14.3)
activesupport (>= 5.0, < 8) activesupport (>= 5.0, < 8)
addressable (~> 2.8) addressable (~> 2.8)
algoliasearch (~> 1.0) algoliasearch (~> 1.0)
@ -62,7 +62,7 @@ GEM
public_suffix (~> 4.0) public_suffix (~> 4.0)
typhoeus (~> 1.0) typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5) cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.6.3) cocoapods-downloader (2.1)
cocoapods-plugins (1.0.0) cocoapods-plugins (1.0.0)
nap nap
cocoapods-search (1.0.1) cocoapods-search (1.0.1)
@ -76,16 +76,15 @@ GEM
highline (~> 2.0.0) highline (~> 2.0.0)
concurrent-ruby (1.2.2) concurrent-ruby (1.2.2)
declarative (0.0.20) declarative (0.0.20)
digest-crc (0.6.4) digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0) rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701) domain_name (0.6.20240107)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.8.1) dotenv (2.8.1)
emoji_regex (3.2.3) emoji_regex (3.2.3)
escape (0.0.4) escape (0.0.4)
ethon (0.16.0) ethon (0.16.0)
ffi (>= 1.15.0) ffi (>= 1.15.0)
excon (0.99.0) excon (0.109.0)
faraday (1.10.3) faraday (1.10.3)
faraday-em_http (~> 1.0) faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0) faraday-em_synchrony (~> 1.0)
@ -114,8 +113,8 @@ GEM
faraday-retry (1.0.3) faraday-retry (1.0.3)
faraday_middleware (1.2.0) faraday_middleware (1.2.0)
faraday (~> 1.0) faraday (~> 1.0)
fastimage (2.2.6) fastimage (2.3.0)
fastlane (2.212.1) fastlane (2.219.0)
CFPropertyList (>= 2.3, < 4.0.0) CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0) addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0) artifactory (~> 3.0)
@ -134,20 +133,22 @@ GEM
gh_inspector (>= 1.1.2, < 2.0.0) gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3) google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1) google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-env (>= 1.6.0, < 2.0.0)
google-cloud-storage (~> 1.31) google-cloud-storage (~> 1.31)
highline (~> 2.0) highline (~> 2.0)
http-cookie (~> 1.0.5)
json (< 3.0.0) json (< 3.0.0)
jwt (>= 2.1.0, < 3) jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0) mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (~> 2.0.0) multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2) naturally (~> 2.2)
optparse (~> 0.1.1) optparse (>= 0.1.1)
plist (>= 3.1.0, < 4.0.0) plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0) rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3) security (= 0.1.3)
simctl (~> 1.6.3) simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0) terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0) terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0) tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0) word_wrap (~> 1.0.0)
@ -159,13 +160,13 @@ GEM
os (~> 1.1, >= 1.1.4) os (~> 1.1, >= 1.1.4)
fastlane-plugin-versioning_android (0.1.1) fastlane-plugin-versioning_android (0.1.1)
fastlane-plugin-yarn (1.2) fastlane-plugin-yarn (1.2)
ffi (1.15.5) ffi (1.16.3)
fourflusher (2.3.1) fourflusher (2.3.1)
fuzzy_match (2.0.4) fuzzy_match (2.0.4)
gh_inspector (1.1.3) gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.35.0) google-apis-androidpublisher_v3 (0.54.0)
google-apis-core (>= 0.11.0, < 2.a) google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.0) google-apis-core (0.11.3)
addressable (~> 2.5, >= 2.5.1) addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a) googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a) httpclient (>= 2.8.1, < 3.a)
@ -173,31 +174,29 @@ GEM
representable (~> 3.0) representable (~> 3.0)
retriable (>= 2.0, < 4.a) retriable (>= 2.0, < 4.a)
rexml rexml
webrick
google-apis-iamcredentials_v1 (0.17.0) google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a) google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0) google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a) google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.19.0) google-apis-storage_v1 (0.31.0)
google-apis-core (>= 0.9.0, < 2.a) google-apis-core (>= 0.11.0, < 2.a)
google-cloud-core (1.6.0) google-cloud-core (1.6.1)
google-cloud-env (~> 1.0) google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0) google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0) google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0) faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.3.1) google-cloud-errors (1.3.1)
google-cloud-storage (1.44.0) google-cloud-storage (1.47.0)
addressable (~> 2.8) addressable (~> 2.8)
digest-crc (~> 0.4) digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1) google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.19.0) google-apis-storage_v1 (~> 0.31.0)
google-cloud-core (~> 1.6) google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a) googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0) mini_mime (~> 1.0)
googleauth (1.3.0) googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a) faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0) jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11) multi_json (~> 1.11)
os (>= 0.9, < 2.0) os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a) signet (>= 0.16, < 2.a)
@ -208,36 +207,35 @@ GEM
i18n (1.12.0) i18n (1.12.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
jmespath (1.6.2) jmespath (1.6.2)
json (2.6.3) json (2.7.1)
jwt (2.7.0) jwt (2.7.1)
memoist (0.16.2)
mini_magick (4.12.0) mini_magick (4.12.0)
mini_mime (1.1.2) mini_mime (1.1.5)
minitest (5.18.0) minitest (5.18.0)
molinillo (0.8.0) molinillo (0.8.0)
multi_json (1.15.0) multi_json (1.15.0)
multipart-post (2.0.0) multipart-post (2.3.0)
nanaimo (0.3.0) nanaimo (0.3.0)
nap (1.1.0) nap (1.1.0)
naturally (2.2.1) naturally (2.2.1)
netrc (0.11.0) netrc (0.11.0)
optparse (0.1.1) optparse (0.4.0)
os (1.1.4) os (1.1.4)
plist (3.7.0) plist (3.7.1)
public_suffix (4.0.7) public_suffix (4.0.7)
rake (13.0.6) rake (13.1.0)
representable (3.2.0) representable (3.2.0)
declarative (< 0.1.0) declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0) trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0) uber (< 0.2.0)
retriable (3.1.2) retriable (3.1.2)
rexml (3.2.5) rexml (3.2.6)
rouge (2.0.7) rouge (2.0.7)
ruby-macho (2.5.1) ruby-macho (2.5.1)
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
rubyzip (2.3.2) rubyzip (2.3.2)
security (0.1.3) security (0.1.3)
signet (0.17.0) signet (0.18.0)
addressable (~> 2.8) addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a) faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0) jwt (>= 1.5, < 3.0)
@ -246,25 +244,21 @@ GEM
CFPropertyList CFPropertyList
naturally naturally
terminal-notifier (2.0.0) terminal-notifier (2.0.0)
terminal-table (1.8.0) terminal-table (3.0.2)
unicode-display_width (~> 1.1, >= 1.1.1) unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2) trailblazer-option (0.1.2)
tty-cursor (0.7.1) tty-cursor (0.7.1)
tty-screen (0.8.1) tty-screen (0.8.2)
tty-spinner (0.9.3) tty-spinner (0.9.3)
tty-cursor (~> 0.7) tty-cursor (~> 0.7)
typhoeus (1.4.0) typhoeus (1.4.1)
ethon (>= 0.9.0) ethon (>= 0.9.0)
tzinfo (2.0.6) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
uber (0.1.0) uber (0.1.0)
unf (0.1.4) unicode-display_width (2.5.0)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
webrick (1.8.1)
word_wrap (1.0.0) word_wrap (1.0.0)
xcodeproj (1.22.0) xcodeproj (1.24.0)
CFPropertyList (>= 2.3.3, < 4.0) CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3) atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0) claide (>= 1.0.2, < 2.0)
@ -280,12 +274,16 @@ PLATFORMS
arm64-darwin-22 arm64-darwin-22
DEPENDENCIES DEPENDENCIES
cocoapods activesupport (>= 6.1.7.5, < 7.1.0)
cocoapods (>= 1.13, < 1.15)
fastlane fastlane
fastlane-plugin-json fastlane-plugin-json
fastlane-plugin-sentry fastlane-plugin-sentry
fastlane-plugin-versioning_android fastlane-plugin-versioning_android
fastlane-plugin-yarn fastlane-plugin-yarn
RUBY VERSION
ruby 3.1.2p20
BUNDLED WITH BUNDLED WITH
2.3.24 2.3.24

View File

@ -8,14 +8,14 @@
Please **do not** create a pull request to update translation. tooot's translation is managed through [https://crowdin.tooot.app/](https://crowdin.tooot.app/) and Crowdin struggles to properly sync two ways. If there is a minor update and you do not want to register an account on Crowdin, please open an issue. Please **do not** create a pull request to update translation. tooot's translation is managed through [https://crowdin.tooot.app/](https://crowdin.tooot.app/) and Crowdin struggles to properly sync two ways. If there is a minor update and you do not want to register an account on Crowdin, please open an issue.
## Special thanks ## Special thanks
- [@a_mento](https://crowdin.com/profile/a_mento) for Basques translation - [@a_mento](https://crowdin.com/profile/a_mento) for Basques translation
- [@dzmitry.zubialevich](https://crowdin.com/profile/dzmitry.zubialevich) for Belarusian translation - [@dzmitry.zubialevich](https://crowdin.com/profile/dzmitry.zubialevich) for Belarusian translation
- [@amrtf](https://crowdin.com/profile/amrtf) for Catalan and Spanish translation - [@amrtf](https://crowdin.com/profile/amrtf) for Catalan and Spanish translation
- [@forenta](https://github.com/forenta) for German translation
- [@pat](https://piaille.fr/@pat) for French translation - [@pat](https://piaille.fr/@pat) for French translation
- [@forenta](https://github.com/forenta) for German translation
- [@heracl.es](https://heracl.es/) for Greek translation
- [@andrigamerita](https://github.com/andrigamerita) for Italian translation - [@andrigamerita](https://github.com/andrigamerita) for Italian translation
- [@Hikaru](https://github.com/Hikali-47041) and [@la_la](https://mstdn.jp/@la_la_la) for Japanese translation - [@Hikaru](https://github.com/Hikali-47041) and [@la_la](https://mstdn.jp/@la_la_la) for Japanese translation
- [@hellojaccc](https://github.com/hellojaccc) for Korean translation - [@hellojaccc](https://github.com/hellojaccc) for Korean translation

View File

@ -1,9 +1,8 @@
apply plugin: "com.android.application" apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react" apply plugin: "com.facebook.react"
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
import com.android.build.OutputFile
/** /**
* This is the configuration block to customize your React Native Android app. * This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need. * By default you don't need to apply any configuration, just uncomment the lines you need.
@ -15,8 +14,8 @@ react {
// root = file("../") // root = file("../")
// The folder where the react-native NPM package is. Default is ../node_modules/react-native // The folder where the react-native NPM package is. Default is ../node_modules/react-native
// reactNativeDir = file("../node_modules/react-native") // reactNativeDir = file("../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
// codegenDir = file("../node_modules/react-native-codegen") // codegenDir = file("../node_modules/@react-native/codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
// cliFile = file("../node_modules/react-native/cli.js") // cliFile = file("../node_modules/react-native/cli.js")
/* Variants */ /* Variants */
@ -51,14 +50,6 @@ react {
// hermesFlags = ["-O", "-output-source-map"] // hermesFlags = ["-O", "-output-source-map"]
} }
/**
* Set this to true to create four separate APKs instead of one,
* one for each native architecture. This is useful if you don't
* use App Bundles (https://developer.android.com/guide/app-bundle/)
* and want to have separate APKs to upload to the Play Store.
*/
def enableSeparateBuildPerCPUArchitecture = false
/** /**
* Set this to true to Run Proguard on Release builds to minify the Java bytecode. * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
*/ */
@ -77,20 +68,11 @@ def enableProguardInReleaseBuilds = false
*/ */
def jscFlavor = 'org.webkit:android-jsc:+' def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Private function to get the list of Native Architectures you want to build.
* This reads the value from reactNativeArchitectures in your gradle.properties
* file and works together with the --active-arch-only flag of react-native run-android.
*/
def reactNativeArchitectures() {
def value = project.getProperties().get("reactNativeArchitectures")
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
android { android {
ndkVersion rootProject.ext.ndkVersion ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
@ -105,14 +87,6 @@ android {
versionCode 50 versionCode 50
versionName "0.2" versionName "0.2"
} }
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include (*reactNativeArchitectures())
}
}
signingConfigs { signingConfigs {
debug { debug {
storeFile file('debug.keystore') storeFile file('debug.keystore')
@ -133,28 +107,9 @@ android {
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
} }
} }
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
}
}
}
} }
dependencies { dependencies {
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.3.0") {
force = true
}
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true"; def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true"; def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true"; def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
@ -182,13 +137,8 @@ dependencies {
// The version of react-native is set by the React Native Gradle Plugin // The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android") implementation("com.facebook.react:react-android")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") implementation("com.facebook.react:flipper-integration")
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
if (hermesEnabled.toBoolean()) { if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android") implementation("com.facebook.react:hermes-android")
} else { } else {

View File

@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application <application
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
tools:targetApi="28" tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning"> tools:ignore="GoogleAppIndexingWarning"/>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" /> </manifest>
</application>
</manifest>

View File

@ -1,72 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.tooot;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
import com.facebook.flipper.core.FlipperClient;
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceEventListener;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
/**
* Class responsible of loading Flipper inside your React Native application. This is the debug
* flavor of it. Here you can add your own plugins and customize the Flipper setup.
*/
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
@Override
public void apply(OkHttpClient.Builder builder) {
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
}
});
client.addPlugin(networkFlipperPlugin);
client.start();
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
// Hence we run if after all native modules have been initialized
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
client.addPlugin(new FrescoFlipperPlugin());
}
});
}
});
} else {
client.addPlugin(new FrescoFlipperPlugin());
}
}
}
}

View File

@ -13,7 +13,7 @@
<!-- [Custom] Expo Notifications --> <!-- [Custom] Expo Notifications -->
<meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/ic_stat_notifications" /> <meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/ic_stat_notifications" />
<!-- [Custom] End Expo Notifications --> <!-- [Custom] End Expo Notifications -->
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:exported="true" android:theme="@style/Theme.App.SplashScreen" android:screenOrientation="portrait" android:documentLaunchMode="never"> <activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:exported="true" android:theme="@style/Theme.App.SplashScreen" android:documentLaunchMode="never">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>

View File

@ -1,42 +0,0 @@
package com.xmflsct.app.tooot;
import android.os.Bundle;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactActivityDelegate;
import expo.modules.ReactActivityDelegateWrapper;
public class MainActivity extends ReactActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
}
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "main";
}
/**
* Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
* DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
* (aka React 18) with two boolean flags.
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new DefaultReactActivityDelegate(
this,
getMainComponentName(),
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
);
}
}

View File

@ -0,0 +1,61 @@
package com.xmflsct.app.tooot;
import android.os.Build
import android.os.Bundle
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
import expo.modules.ReactActivityDelegateWrapper
class MainActivity : ReactActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen.
setTheme(R.style.AppTheme);
super.onCreate(null)
}
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
override fun getMainComponentName(): String = "main"
/**
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/
override fun createReactActivityDelegate(): ReactActivityDelegate {
return ReactActivityDelegateWrapper(
this,
BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
object : DefaultReactActivityDelegate(
this,
mainComponentName,
fabricEnabled
){})
}
/**
* Align the back button behavior with Android S
* where moving root activities to background instead of finishing activities.
* @see <a href="https://developer.android.com/reference/android/app/Activity#onBackPressed()">onBackPressed</a>
*/
override fun invokeDefaultOnBackPressed() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
if (!moveTaskToBack(false)) {
// For non-root activities, use the default implementation to finish them.
super.invokeDefaultOnBackPressed()
}
return
}
// Use the default back button implementation on Android S
// because it's doing more than [Activity.moveTaskToBack] in fact.
super.invokeDefaultOnBackPressed()
}
}

View File

@ -1,69 +0,0 @@
package com.xmflsct.app.tooot;
import android.app.Application;
import android.content.res.Configuration;
import androidx.annotation.NonNull;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import expo.modules.ApplicationLifecycleDispatcher;
import expo.modules.ReactNativeHostWrapper;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHostWrapper(
this,
new DefaultReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@Override
protected boolean isNewArchEnabled() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}
@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
});
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
DefaultNewArchitectureEntryPoint.load();
}
// ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
}

View File

@ -0,0 +1,58 @@
package com.xmflsct.app.tooot;
import android.app.Application
import android.content.res.Configuration
import androidx.annotation.NonNull
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.flipper.ReactNativeFlipper
import com.facebook.soloader.SoLoader
import expo.modules.ApplicationLifecycleDispatcher
import expo.modules.ReactNativeHostWrapper
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
this,
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> {
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return PackageList(this).packages
}
override fun getJSMainModuleName(): String = "index"
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}
)
override val reactHost: ReactHost
get() = getDefaultReactHost(this.applicationContext, reactNativeHost)
override fun onCreate() {
super.onCreate()
SoLoader.init(this, false)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
ApplicationLifecycleDispatcher.onApplicationCreate(this)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
}
}

View File

@ -1,20 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.rndiffapp;
import android.content.Context;
import com.facebook.react.ReactInstanceManager;
/**
* Class responsible of loading Flipper inside your React Native application. This is the release
* flavor of it so it's empty as we don't want to load Flipper.
*/
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
// Do nothing as we don't want to initialize Flipper on Release.
}
}

View File

@ -1,15 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext { ext {
buildToolsVersion = "33.0.0" buildToolsVersion = "34.0.0"
minSdkVersion = 21 minSdkVersion = 21
compileSdkVersion = 33 compileSdkVersion = 34
targetSdkVersion = 33 targetSdkVersion = 34
kotlinVersion = '1.8.10' ndkVersion = "25.1.8937393"
kotlinVersion = '1.8.0'
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
ndkVersion = "23.1.7779620"
} }
repositories { repositories {
google() google()
@ -17,8 +13,11 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:7.4.1") classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin") classpath("com.facebook.react:react-native-gradle-plugin")
classpath 'com.google.gms:google-services:4.3.14' classpath 'com.google.gms:google-services:4.3.14'
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
} }
} }
apply plugin: "com.facebook.react.rootproject"

View File

@ -25,9 +25,6 @@ android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true android.enableJetifier=true
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.176.1
# Use this property to specify which architecture you want to build. # Use this property to specify which architecture you want to build.
# You can also override it from the CLI using # You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64 # ./gradlew <task> -PreactNativeArchitectures=x86_64
@ -43,10 +40,10 @@ newArchEnabled=false
# If set to false, you will be using JSC instead. # If set to false, you will be using JSC instead.
hermesEnabled=true hermesEnabled=true
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=4096m -XX:+HeapDumpOnOutOfMemoryError org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
org.gradle.daemon=true # org.gradle.daemon=true
org.gradle.parallel=true # org.gradle.parallel=true
org.gradle.configureondemand=true # org.gradle.configureondemand=true
# The hosted JavaScript engine # The hosted JavaScript engine
# Supported values: expo.jsEngine = "hermes" | "jsc" # Supported values: expo.jsEngine = "hermes" | "jsc"

Binary file not shown.

View File

@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

81
android/gradlew vendored
View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# #
# Copyright 2015 the original author or authors. # Copyright © 2015-2021 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -17,14 +17,56 @@
# #
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
app_path=$0 app_path=$0
# Need this for daisy-chained symlinks. # Need this for daisy-chained symlinks.
while while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
@ -37,13 +79,11 @@ do
*) app_path=$APP_HOME$link ;; *) app_path=$APP_HOME$link ;;
esac esac
done done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@ -73,6 +113,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@ -89,22 +130,29 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
case $MAX_FD in #( case $MAX_FD in #(
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@ -122,7 +170,9 @@ fi
if "$cygwin" || "$msys" ; then if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" ) JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh # Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do for arg do
if if
@ -147,16 +197,27 @@ if "$cygwin" || "$msys" ; then
done done
fi fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in # shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and # double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded. # * put everything else in single quotes, so that it's not re-expanded.
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \ -classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \ org.gradle.wrapper.GradleWrapperMain \
"$@" "$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args. # Use "xargs" to parse quoted args.
# #
# With -n1 it outputs one arg per line, with the quotes and backslashes removed. # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
@ -183,4 +244,4 @@ eval "set -- $(
tr '\n' ' ' tr '\n' ' '
)" '"$@"' )" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

17
android/gradlew.bat vendored
View File

@ -14,7 +14,7 @@
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -69,20 +69,23 @@ goto fail
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 set EXIT_CODE=%ERRORLEVEL%
exit /b 1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal
:omega :omega

View File

@ -1,11 +1,10 @@
rootProject.name = 'tooot' rootProject.name = 'tooot'
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute().text.trim(), "../scripts/autolinking.gradle"); apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
useExpoModules() useExpoModules()
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute().text.trim(), "../native_modules.gradle"); apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
applyNativeModulesSettingsGradle(settings) applyNativeModulesSettingsGradle(settings)
include ':app' include ':app'
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile())
includeBuild('../node_modules/react-native-gradle-plugin')

View File

@ -1,26 +1,27 @@
module.exports = function (api) { module.exports = function (api) {
api.cache(false) api.cache(false)
const plugins = [ return {
'@babel/plugin-proposal-optional-chaining', presets: ['babel-preset-expo'],
[ plugins: [
'module-resolver', '@babel/plugin-proposal-optional-chaining',
{ [
root: ['./'], 'module-resolver',
alias: { {
'@components': './src/components', root: ['./'],
'@i18n': './src/i18n', alias: {
'@screens': './src/screens', '@components': './src/components',
'@utils': './src/utils' '@i18n': './src/i18n',
'@screens': './src/screens',
'@utils': './src/utils'
}
} }
} ]
], ].concat(
'react-native-reanimated/plugin' process.env.NODE_ENV === 'production' || process.env.BABEL_ENV === 'production'
] ? ['transform-remove-console']
: [],
if (process.env.NODE_ENV === 'production' || process.env.BABEL_ENV === 'production') { ['react-native-reanimated/plugin']
plugins.push('transform-remove-console') )
} }
return { presets: ['babel-preset-expo'], plugins }
} }

View File

@ -1,3 +1 @@
Enjoy toooting! This version includes following improvements and fixes: Enjoy toooting! This version includes improvements and fixes.
- Added Basque language
- Added Polish language

View File

@ -1,4 +1 @@
toooting愉快此版本包括以下改进和修复 tooot-ing愉快此版本包括改进和修复。
- 添加neodb.social书影音展示卡片
- 新增巴斯克语
- 新增波兰语

View File

@ -1,8 +1,13 @@
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking") require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
require File.join(File.dirname(`node --print "require.resolve('@react-native-community/cli-platform-ios/package.json')"`), "native_modules")
platform :ios, '13.0' # Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
'require.resolve(
"react-native/scripts/react_native_pods.rb",
{paths: [process.argv[1]]},
)', __dir__]).strip
platform :ios, '13.4'
prepare_react_native_project! prepare_react_native_project!
flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
linkage = ENV['USE_FRAMEWORKS'] linkage = ENV['USE_FRAMEWORKS']
@ -18,13 +23,8 @@ target 'tooot' do
use_expo_modules! use_expo_modules!
config = use_native_modules! config = use_native_modules!
# Flags change depending on the env values.
flags = get_default_flags()
use_react_native!( use_react_native!(
:path => config[:reactNativePath], :path => config[:reactNativePath],
:hermes_enabled => true,
:fabric_enabled => flags[:fabric_enabled],
:flipper_configuration => FlipperConfiguration.disabled, :flipper_configuration => FlipperConfiguration.disabled,
# An absolute path to your application root. # An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.." :app_path => "#{Pod::Config.instance.installation_root}/.."
@ -33,11 +33,9 @@ target 'tooot' do
post_install do |installer| post_install do |installer|
react_native_post_install( react_native_post_install(
installer, installer,
# Set `mac_catalyst_enabled` to `true` in order to apply patches config[:reactNativePath],
# necessary for Mac Catalyst builds
:mac_catalyst_enabled => false :mac_catalyst_enabled => false
) )
__apply_Xcode_12_5_M1_post_install_workaround(installer)
# For share extension # For share extension
installer.pods_project.targets.each do |target| installer.pods_project.targets.each do |target|
@ -45,15 +43,6 @@ target 'tooot' do
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No' config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No'
end end
end end
# For Xcode 14
installer.generated_projects.each do |project|
project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
end
end
end
end end
post_integrate do |installer| post_integrate do |installer|
@ -67,7 +56,6 @@ end
target 'ShareExtension' do target 'ShareExtension' do
use_react_native!( use_react_native!(
:hermes_enabled => true,
:flipper_configuration => FlipperConfiguration.disabled :flipper_configuration => FlipperConfiguration.disabled
) )

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
"NSPhotoLibraryAddUsageDescription" = "Επιτρέψτε στο tooot να αποθηκεύει εικόνες στο ρολό της κάμερας";
"NSPhotoLibraryUsageDescription" = "Επιτρέψτε στο tooot να αποθηκεύει εικόνες στο ρολό της κάμερας";

View File

@ -77,6 +77,7 @@
E633A42F281EAF38000E540F /* ShareViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShareViewController.swift; path = "../../node_modules/react-native-share-menu/ios/ShareViewController.swift"; sourceTree = "<group>"; }; E633A42F281EAF38000E540F /* ShareViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShareViewController.swift; path = "../../node_modules/react-native-share-menu/ios/ShareViewController.swift"; sourceTree = "<group>"; };
E633A431281EB55C000E540F /* ShareExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ShareExtension-Bridging-Header.h"; sourceTree = "<group>"; }; E633A431281EB55C000E540F /* ShareExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ShareExtension-Bridging-Header.h"; sourceTree = "<group>"; };
E63E7FF0292A828100C76FD4 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = "<group>"; }; E63E7FF0292A828100C76FD4 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E65BA25629EDEF8C008E0BBC /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = el.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E66C0842291F095800DFFF60 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; }; E66C0842291F095800DFFF60 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E671BDF8290EAFB800287BD0 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; }; E671BDF8290EAFB800287BD0 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
E690907B29C1133000489554 /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = eu.lproj/InfoPlist.strings; sourceTree = "<group>"; }; E690907B29C1133000489554 /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = eu.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@ -224,6 +225,7 @@
buildPhases = ( buildPhases = (
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */, 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */, FD10A7F022414F080027D42C /* Start Packager */,
395686AEA3960C8699AE1CAD /* [Expo] Configure project */,
13B07F871A680F5B00A75B9A /* Sources */, 13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */, 13B07F8E1A680F5B00A75B9A /* Resources */,
@ -308,6 +310,7 @@
be, be,
eu, eu,
pl, pl,
el,
); );
mainGroup = 83CBB9F61A601CBA00E9B192; mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
@ -383,6 +386,25 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
395686AEA3960C8699AE1CAD /* [Expo] Configure project */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "[Expo] Configure project";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-tooot/expo-configure-project.sh\"\n";
};
49D30A53634620EF2A5C6692 /* [CP] Embed Pods Frameworks */ = { 49D30A53634620EF2A5C6692 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -409,12 +431,14 @@
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-resources.sh", "${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
"${PODS_ROOT}/Sentry/Sources/Resources/PrivacyInfo.xcprivacy",
); );
name = "[CP] Copy Pods Resources"; name = "[CP] Copy Pods Resources";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/PrivacyInfo.xcprivacy",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
@ -450,11 +474,11 @@
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShareExtension/Pods-ShareExtension-resources.sh", "${PODS_ROOT}/Target Support Files/Pods-ShareExtension/Pods-ShareExtension-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
); );
name = "[CP] Copy Pods Resources"; name = "[CP] Copy Pods Resources";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
@ -545,6 +569,7 @@
E6179D6E29B94551001930D5 /* be */, E6179D6E29B94551001930D5 /* be */,
E690907B29C1133000489554 /* eu */, E690907B29C1133000489554 /* eu */,
E6B76A1E29C1147B00187ABB /* pl */, E6B76A1E29C1147B00187ABB /* pl */,
E65BA25629EDEF8C008E0BBC /* el */,
); );
name = InfoPlist.strings; name = InfoPlist.strings;
sourceTree = "<group>"; sourceTree = "<group>";
@ -571,7 +596,7 @@
); );
INFOPLIST_FILE = tooot/Info.plist; INFOPLIST_FILE = tooot/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -586,8 +611,8 @@
PRODUCT_NAME = tooot; PRODUCT_NAME = tooot;
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.xmflsct.app.tooot"; PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.xmflsct.app.tooot";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = YES; SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_PRECOMPILE_BRIDGING_HEADER = YES; SWIFT_PRECOMPILE_BRIDGING_HEADER = YES;
@ -611,7 +636,7 @@
"ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES; "ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES;
INFOPLIST_FILE = tooot/Info.plist; INFOPLIST_FILE = tooot/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -626,8 +651,8 @@
PRODUCT_NAME = tooot; PRODUCT_NAME = tooot;
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.xmflsct.app.tooot"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.xmflsct.app.tooot";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = YES; SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
SWIFT_PRECOMPILE_BRIDGING_HEADER = YES; SWIFT_PRECOMPILE_BRIDGING_HEADER = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@ -641,7 +666,7 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
@ -678,6 +703,7 @@
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
); );
GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -694,8 +720,12 @@
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"\""; LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"\"";
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos; SDKROOT = iphoneos;
USE_HERMES = true;
}; };
name = Debug; name = Debug;
}; };
@ -704,7 +734,7 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
@ -736,6 +766,10 @@
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
@ -750,9 +784,13 @@
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"\""; LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"\"";
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
ONLY_ACTIVE_ARCH = NO; ONLY_ACTIVE_ARCH = NO;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;
USE_HERMES = true;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = Release; name = Release;
@ -779,8 +817,7 @@
INFOPLIST_FILE = ShareExtension/Info.plist; INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension; INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.4;
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -795,7 +832,8 @@
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.xmflsct.app.tooot.ShareExtension"; PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.xmflsct.app.tooot.ShareExtension";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match AdHoc com.xmflsct.app.tooot.ShareExtension"; "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match AdHoc com.xmflsct.app.tooot.ShareExtension";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = YES; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h";
@ -829,8 +867,7 @@
INFOPLIST_FILE = ShareExtension/Info.plist; INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension; INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.4;
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -844,7 +881,8 @@
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.xmflsct.app.tooot.ShareExtension"; PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.xmflsct.app.tooot.ShareExtension";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match AppStore com.xmflsct.app.tooot.ShareExtension"; "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match AppStore com.xmflsct.app.tooot.ShareExtension";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = YES; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_OPTIMIZATION_LEVEL = "-O";

View File

@ -14,6 +14,10 @@
} }
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
return [self getBundleURL];
}
- (NSURL *)getBundleURL
{ {
#if DEBUG #if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
@ -22,16 +26,6 @@
#endif #endif
} }
/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
///
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`.
- (BOOL)concurrentRootEnabled
{
return true;
}
// Linking API // Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
NSString *urlString = url.absoluteString; NSString *urlString = url.absoluteString;

View File

@ -35,6 +35,7 @@
<array> <array>
<string>tooot-share</string> <string>tooot-share</string>
<string>tooot</string> <string>tooot</string>
<string>https</string>
</array> </array>
</dict> </dict>
</array> </array>
@ -48,14 +49,11 @@
<true/> <true/>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
<dict> <dict>
<key>NSExceptionDomains</key> <!-- Do not change NSAllowsArbitraryLoads to true, or you will risk app rejection! -->
<dict> <key>NSAllowsArbitraryLoads</key>
<key>localhost</key> <false/>
<dict> <key>NSAllowsLocalNetworking</key>
<key>NSExceptionAllowsInsecureHTTPLoads</key> <true/>
<true/>
</dict>
</dict>
</dict> </dict>
<key>NSLocationWhenInUseUsageDescription</key> <key>NSLocationWhenInUseUsageDescription</key>
<string></string> <string></string>

View File

@ -1,3 +1,11 @@
module.exports = { const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config')
transformer: { inlineRequires: true }
} /**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const config = {};
module.exports = mergeConfig(getDefaultConfig(__dirname), config)

View File

@ -1,6 +1,6 @@
{ {
"name": "tooot", "name": "tooot",
"version": "4.9.2", "version": "4.11.0",
"description": "tooot for Mastodon", "description": "tooot for Mastodon",
"author": "xmflsct <me@xmflsct.com>", "author": "xmflsct <me@xmflsct.com>",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
@ -12,108 +12,110 @@
"start": "react-native start", "start": "react-native start",
"android": "react-native run-android", "android": "react-native run-android",
"phone": "react-native run-ios --device", "phone": "react-native run-ios --device",
"iphone": "react-native run-ios --simulator 'iPhone 14 Pro'", "iphone": "react-native run-ios --simulator 'iPhone 15 Pro'",
"ipad": "react-native run-ios --simulator 'iPad Pro (11-inch) (4th generation)'", "ipad": "react-native run-ios --simulator 'iPad Pro (11-inch) (4th generation)'",
"app:build": "bundle exec fastlane", "app:build": "bundle exec fastlane",
"clean": "react-native-clean-project" "clean": "react-native-clean-project"
}, },
"dependencies": { "dependencies": {
"@expo/react-native-action-sheet": "^4.0.1", "@expo/react-native-action-sheet": "^4.0.1",
"@formatjs/intl-datetimeformat": "^6.5.1", "@formatjs/intl-datetimeformat": "^6.12.2",
"@formatjs/intl-getcanonicallocales": "^2.1.0", "@formatjs/intl-getcanonicallocales": "^2.3.0",
"@formatjs/intl-locale": "^3.1.1", "@formatjs/intl-locale": "^3.4.5",
"@formatjs/intl-numberformat": "^8.3.5", "@formatjs/intl-numberformat": "^8.10.0",
"@formatjs/intl-pluralrules": "^5.1.10", "@formatjs/intl-pluralrules": "^5.2.12",
"@formatjs/intl-relativetimeformat": "^11.1.10", "@formatjs/intl-relativetimeformat": "^11.2.12",
"@mattermost/react-native-paste-input": "^0.6.2", "@mattermost/react-native-paste-input": "^0.7.0",
"@neverdull-agency/expo-unlimited-secure-store": "^1.0.10", "@neverdull-agency/expo-unlimited-secure-store": "^1.0.10",
"@react-native-async-storage/async-storage": "~1.17.11", "@react-native-async-storage/async-storage": "~1.21.0",
"@react-native-camera-roll/camera-roll": "^5.3.1", "@react-native-camera-roll/camera-roll": "^7.4.0",
"@react-native-clipboard/clipboard": "^1.11.2", "@react-native-clipboard/clipboard": "^1.13.2",
"@react-native-community/blur": "^4.3.0", "@react-native-community/blur": "^4.4.0",
"@react-native-community/netinfo": "9.3.7", "@react-native-community/netinfo": "^11.2.1",
"@react-native-firebase/app": "^17.3.2", "@react-native-firebase/app": "^18.8.0",
"@react-native-menu/menu": "^0.7.3", "@react-native-menu/menu": "^0.9.1",
"@react-native-segmented-control/segmented-control": "^2.4.0", "@react-native-segmented-control/segmented-control": "^2.5.0",
"@react-navigation/bottom-tabs": "^6.5.7", "@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.6", "@react-navigation/native": "^6.1.9",
"@react-navigation/native-stack": "^6.9.12", "@react-navigation/native-stack": "^6.9.17",
"@react-navigation/stack": "^6.3.16", "@react-navigation/stack": "^6.3.20",
"@sentry/react-native": "5.1.1", "@sentry/react-native": "^5.18.0",
"@sharcoux/slider": "^6.1.1", "@sharcoux/slider": "^7.1.1",
"@tanstack/react-query": "^4.26.1", "@tanstack/react-query": "^4.36.1",
"axios": "^1.3.4", "axios": "^1.6.7",
"diff": "^5.1.0", "diff": "^5.1.0",
"expo": "48.0.7", "expo": "^50.0.6",
"expo-auth-session": "^4.0.3", "expo-auth-session": "^5.4.0",
"expo-av": "^13.2.1", "expo-av": "^13.10.5",
"expo-constants": "^14.2.1", "expo-constants": "^15.4.5",
"expo-crypto": "^12.2.1", "expo-crypto": "^12.8.0",
"expo-file-system": "^15.2.2", "expo-file-system": "^16.0.6",
"expo-haptics": "^12.2.1", "expo-haptics": "^12.8.1",
"expo-image": "^1.0.0", "expo-image": "^1.11.0",
"expo-linking": "^4.0.1", "expo-linking": "^6.2.2",
"expo-localization": "^14.1.1", "expo-localization": "^14.8.3",
"expo-notifications": "^0.18.1", "expo-notifications": "^0.27.6",
"expo-screen-capture": "^5.1.1", "expo-screen-capture": "^5.8.1",
"expo-screen-orientation": "^5.1.1", "expo-screen-orientation": "^6.4.1",
"expo-secure-store": "^12.1.1", "expo-secure-store": "^12.8.1",
"expo-splash-screen": "^0.18.1", "expo-splash-screen": "^0.26.4",
"expo-store-review": "^6.2.1", "expo-store-review": "^6.8.3",
"expo-video-thumbnails": "^7.2.1", "expo-video-thumbnails": "^7.9.0",
"expo-web-browser": "~12.1.1", "expo-web-browser": "^12.8.2",
"htmlparser2": "^8.0.1", "htmlparser2": "^9.1.0",
"i18next": "^22.4.11", "i18next": "^23.8.2",
"linkify-it": "^4.0.1", "linkify-it": "^5.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-i18next": "^12.2.0", "react-i18next": "^14.0.5",
"react-intl": "^6.2.10", "react-intl": "^6.6.2",
"react-native": "^0.71.4", "react-native": "^0.73.4",
"react-native-flash-message": "^0.4.0", "react-native-flash-message": "^0.4.2",
"react-native-gesture-handler": "~2.9.0", "react-native-gesture-handler": "^2.15.0",
"react-native-image-picker": "^5.3.1", "react-native-image-picker": "^7.1.0",
"react-native-ios-context-menu": "^1.15.3", "react-native-ios-context-menu": "^2.3.2",
"react-native-ios-utilities": "^4.3.0",
"react-native-language-detection": "^0.2.2", "react-native-language-detection": "^0.2.2",
"react-native-mmkv": "~2.7.0", "react-native-mmkv": "^2.11.0",
"react-native-pager-view": "^6.1.4", "react-native-pager-view": "^6.2.3",
"react-native-quick-base64": "^2.0.5", "react-native-quick-base64": "^2.0.8",
"react-native-reanimated": "^3.0.2", "react-native-reanimated": "^3.6.2",
"react-native-reanimated-zoom": "^0.3.3", "react-native-reanimated-zoom": "^0.3.3",
"react-native-safe-area-context": "^4.5.0", "react-native-safe-area-context": "^4.9.0",
"react-native-screens": "^3.20.0", "react-native-screens": "^3.29.0",
"react-native-share-menu": "^6.0.0", "react-native-share-menu": "^6.0.0",
"react-native-svg": "^13.8.0", "react-native-svg": "^14.1.0",
"react-native-swipe-list-view": "^3.2.9", "react-native-swipe-list-view": "^3.2.9",
"react-native-tab-view": "^3.5.1", "react-native-tab-view": "^3.5.2",
"rn-placeholder": "^3.0.3", "rn-placeholder": "^3.0.3",
"zeego": "^1.4.1" "zeego": "^1.7.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.21.3", "@babel/core": "^7.23.9",
"@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/plugin-proposal-optional-chaining": "^7.21.0",
"@babel/preset-typescript": "^7.21.0", "@babel/preset-typescript": "^7.23.3",
"@expo/config": "^8.0.2", "@expo/config": "^8.5.4",
"@types/diff": "^5.0.2", "@react-native/metro-config": "^0.73.5",
"@types/linkify-it": "^3.0.2", "@react-native/typescript-config": "^0.74.0",
"@types/lodash": "^4.14.191", "@types/diff": "^5.0.9",
"@types/react": "^18.0.28", "@types/linkify-it": "^3.0.5",
"@types/react-dom": "^18.0.11", "@types/lodash": "^4.14.202",
"@types/react-native-share-menu": "^5.0.2", "@types/react": "^18.2.55",
"@types/react-dom": "^18.2.18",
"@types/react-native-share-menu": "^5.0.5",
"babel-plugin-module-resolver": "^5.0.0", "babel-plugin-module-resolver": "^5.0.0",
"babel-plugin-transform-remove-console": "^6.9.4", "babel-plugin-transform-remove-console": "^6.9.4",
"chalk": "^4.1.2", "chalk": "^4.1.2",
"deprecated-react-native-prop-types": "^4.0.0", "dotenv": "^16.4.1",
"dotenv": "^16.0.3", "react-native-clean-project": "^4.0.3",
"react-native-clean-project": "^4.0.1", "typescript": "^5.3.3"
"typescript": "^4.9.5"
}, },
"packageManager": "yarn@3.3.1", "packageManager": "yarn@4.1.0",
"resolutions": { "resolutions": {
"expo-av@^13.0.2": "patch:expo-av@npm%3A13.0.2#./.yarn/patches/expo-av-npm-13.0.2-7a651776f1.patch",
"react-native-share-menu@^6.0.0": "patch:react-native-share-menu@npm%3A6.0.0#./.yarn/patches/react-native-share-menu-npm-6.0.0-f1094c3204.patch", "react-native-share-menu@^6.0.0": "patch:react-native-share-menu@npm%3A6.0.0#./.yarn/patches/react-native-share-menu-npm-6.0.0-f1094c3204.patch",
"@types/react-native-share-menu@^5.0.2": "patch:@types/react-native-share-menu@npm%3A5.0.2#./.yarn/patches/@types-react-native-share-menu-npm-5.0.2-373df17ecc.patch", "@types/react-native-share-menu@^5.0.2": "patch:@types/react-native-share-menu@npm%3A5.0.2#./.yarn/patches/@types-react-native-share-menu-npm-5.0.2-373df17ecc.patch",
"react-native-ios-context-menu@^1.15.1": "patch:react-native-ios-context-menu@npm%3A1.15.1#./.yarn/patches/react-native-ios-context-menu-npm-1.15.1-0034bfa5ba.patch" "react-native-ios-context-menu@^2.3.2": "patch:react-native-ios-context-menu@npm%3A2.3.2#~/.yarn/patches/react-native-ios-context-menu-npm-2.3.2-9099ed7858.patch",
"react-native-reanimated-zoom@^0.3.3": "patch:react-native-reanimated-zoom@npm%3A0.3.3#./.yarn/patches/react-native-reanimated-zoom-npm-0.3.3-bbb8d84109.patch"
} }
} }

View File

@ -4,9 +4,10 @@ import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import React, { PropsWithChildren, useState } from 'react' import React, { PropsWithChildren, useState } from 'react'
import { Dimensions, Pressable, View } from 'react-native' import { Dimensions, Pressable, Text, View } from 'react-native'
import Sparkline from './Sparkline' import Sparkline from './Sparkline'
import CustomText from './Text' import CustomText from './Text'
import { sumBy } from 'lodash'
export interface Props { export interface Props {
hashtag: Mastodon.Tag hashtag: Mastodon.Tag
@ -29,6 +30,8 @@ const ComponentHashtag: React.FC<PropsWithChildren & Props> = ({
const width = Dimensions.get('window').width / 4 const width = Dimensions.get('window').width / 4
const [height, setHeight] = useState<number>(0) const [height, setHeight] = useState<number>(0)
const sum = sumBy(hashtag.history, h => parseInt(h.uses))
return ( return (
<Pressable <Pressable
accessibilityRole='button' accessibilityRole='button'
@ -41,17 +44,24 @@ const ComponentHashtag: React.FC<PropsWithChildren & Props> = ({
}} }}
onPress={customOnPress || onPress} onPress={customOnPress || onPress}
> >
<CustomText <View
fontStyle='M'
style={{ style={{
flexShrink: 1, flexShrink: 1,
color: colors.primaryDefault,
paddingRight: StyleConstants.Spacing.M paddingRight: StyleConstants.Spacing.M
}} }}
numberOfLines={1}
> >
#{hashtag.name} <CustomText fontStyle='M' style={{ color: colors.primaryDefault }} numberOfLines={1}>
</CustomText> #{hashtag.name}
{sum ? (
<>
{' '}
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
({sumBy(hashtag.history, h => parseInt(h.uses))})
</CustomText>
</>
) : null}
</CustomText>
</View>
{hashtag.history?.length ? ( {hashtag.history?.length ? (
<View <View
style={{ flexDirection: 'row', alignItems: 'center', alignSelf: 'stretch' }} style={{ flexDirection: 'row', alignItems: 'center', alignSelf: 'stretch' }}
@ -66,6 +76,7 @@ const ComponentHashtag: React.FC<PropsWithChildren & Props> = ({
width={width} width={width}
height={height} height={height}
margin={children ? StyleConstants.Spacing.S : undefined} margin={children ? StyleConstants.Spacing.S : undefined}
color={!sum ? colors.disabled : undefined}
/> />
{children} {children}
</View> </View>

View File

@ -1,5 +1,6 @@
import Icon, { IconName } from '@components/Icon' import Icon, { IconName } from '@components/Icon'
import CustomText from '@components/Text' import CustomText from '@components/Text'
import { useNavigation } from '@react-navigation/native'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react' import React from 'react'
@ -9,7 +10,7 @@ export type Props = {
native?: boolean native?: boolean
background?: boolean background?: boolean
onPress: () => void onPress?: () => void
} & ({ type?: undefined; content?: IconName } | { type: 'text'; content: string }) } & ({ type?: undefined; content?: IconName } | { type: 'text'; content: string })
const HeaderLeft: React.FC<Props> = ({ const HeaderLeft: React.FC<Props> = ({
@ -19,6 +20,7 @@ const HeaderLeft: React.FC<Props> = ({
background = false, background = false,
onPress onPress
}) => { }) => {
const navigation = useNavigation()
const { colors } = useTheme() const { colors } = useTheme()
const children = () => { const children = () => {
@ -40,7 +42,7 @@ const HeaderLeft: React.FC<Props> = ({
return ( return (
<Pressable <Pressable
onPress={onPress} onPress={onPress ? onPress : () => navigation.goBack()}
children={children()} children={children()}
style={{ style={{
flexDirection: 'row', flexDirection: 'row',

View File

@ -17,6 +17,7 @@ export type Props = {
loading?: boolean loading?: boolean
disabled?: boolean disabled?: boolean
destructive?: boolean destructive?: boolean
destructiveColor?: string
onPress: () => void onPress: () => void
} & ({ type?: undefined; content: IconName } | { type: 'text'; content: string }) } & ({ type?: undefined; content: IconName } | { type: 'text'; content: string })
@ -34,6 +35,7 @@ const HeaderRight: React.FC<Props> = ({
loading, loading,
disabled, disabled,
destructive = false, destructive = false,
destructiveColor,
onPress onPress
}) => { }) => {
const { colors } = useTheme() const { colors } = useTheme()
@ -57,7 +59,7 @@ const HeaderRight: React.FC<Props> = ({
color: disabled color: disabled
? colors.secondary ? colors.secondary
: destructive : destructive
? colors.red ? destructiveColor || colors.red
: colors.primaryDefault, : colors.primaryDefault,
opacity: loading ? 0 : 1 opacity: loading ? 0 : 1
}} }}

View File

@ -22,7 +22,6 @@ import * as AuthSession from 'expo-auth-session'
import * as Crypto from 'expo-crypto' import * as Crypto from 'expo-crypto'
import { Image } from 'expo-image' import { Image } from 'expo-image'
import * as Linking from 'expo-linking' import * as Linking from 'expo-linking'
import * as WebBrowser from 'expo-web-browser'
import { debounce } from 'lodash' import { debounce } from 'lodash'
import React, { RefObject, useCallback, useState } from 'react' import React, { RefObject, useCallback, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
@ -30,6 +29,7 @@ import { Alert, KeyboardAvoidingView, Platform, TextInput, View } from 'react-na
import { ScrollView } from 'react-native-gesture-handler' import { ScrollView } from 'react-native-gesture-handler'
import { fromByteArray } from 'react-native-quick-base64' import { fromByteArray } from 'react-native-quick-base64'
import CustomText from '../Text' import CustomText from '../Text'
import openLink from '@components/openLink'
export interface Props { export interface Props {
scrollViewRef?: RefObject<ScrollView> scrollViewRef?: RefObject<ScrollView>
@ -52,7 +52,7 @@ const ComponentInstance: React.FC<Props> = ({
!!domain.length && !!domain.length &&
!!errorCode && !!errorCode &&
!!(Linking.parse(`https://${domain}/`).hostname === domain) && !!(Linking.parse(`https://${domain}/`).hostname === domain) &&
errorCode === 401 (errorCode === 401 || errorCode === 500)
const instanceQuery = useInstanceQuery({ const instanceQuery = useInstanceQuery({
domain, domain,
@ -131,7 +131,8 @@ const ComponentInstance: React.FC<Props> = ({
((instanceQuery.data as Mastodon.Instance_V1)?.uri ((instanceQuery.data as Mastodon.Instance_V1)?.uri
? Linking.parse((instanceQuery.data as Mastodon.Instance_V1).uri).hostname ? Linking.parse((instanceQuery.data as Mastodon.Instance_V1).uri).hostname
: undefined) || : undefined) ||
(instanceQuery.data as Mastodon.Instance_V1)?.uri, (instanceQuery.data as Mastodon.Instance_V1)?.uri ||
domain,
'auth.account.avatar_static': avatar_static, 'auth.account.avatar_static': avatar_static,
version: instanceQuery.data?.version || '0', version: instanceQuery.data?.version || '0',
preferences: undefined, preferences: undefined,
@ -386,20 +387,12 @@ const ComponentInstance: React.FC<Props> = ({
<CustomText <CustomText
accessible accessible
style={{ color: colors.blue }} style={{ color: colors.blue }}
onPress={async () => onPress={async () => openLink('https://tooot.app/privacy-policy')}
WebBrowser.openBrowserAsync('https://tooot.app/privacy-policy', {
...(await browserPackage())
})
}
/>, />,
<CustomText <CustomText
accessible accessible
style={{ color: colors.blue }} style={{ color: colors.blue }}
onPress={async () => onPress={async () => openLink('https://tooot.app/terms-of-service')}
WebBrowser.openBrowserAsync('https://tooot.app/terms-of-service', {
...(await browserPackage())
})
}
/> />
]} ]}
/> />

View File

@ -223,7 +223,7 @@ const ParseHTML: React.FC<Props> = ({
key={index} key={index}
style={{ lineHeight: adaptedLineheight ? adaptedLineheight / 2 : undefined }} style={{ lineHeight: adaptedLineheight ? adaptedLineheight / 2 : undefined }}
> >
{'\n'} {'\n\n'}
</Text> </Text>
) )
case 'p': case 'p':

View File

@ -1,18 +1,18 @@
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react' import React from 'react'
import { Pressable, View } from 'react-native' import { Pressable, View } from 'react-native'
import haptics from './haptics'
import Icon from './Icon' import Icon from './Icon'
import { ParseEmojis } from './Parse' import { ParseEmojis } from './Parse'
import CustomText from './Text' import CustomText from './Text'
import haptics from './haptics'
export interface Props { export interface Props {
title?: string title?: string
multiple?: boolean multiple?: boolean
options: { selected: boolean; content: string }[] options: { selected: boolean; content: string }[]
setOptions: React.Dispatch<React.SetStateAction<{ selected: boolean; content: string }[]>> setOptions: React.Dispatch<React.SetStateAction<any>>
disabled?: boolean disabled?: boolean
invalid?: boolean invalid?: boolean
} }

View File

@ -22,7 +22,7 @@ const ComponentSeparator: React.FC<Props> = ({
style, style,
{ {
backgroundColor: colors.backgroundDefault, backgroundColor: colors.backgroundDefault,
borderTopColor: colors.border, borderTopColor: colors.separator,
borderTopWidth: 1, borderTopWidth: 1,
marginLeft: StyleConstants.Spacing.Global.PagePadding + extraMarginLeft, marginLeft: StyleConstants.Spacing.Global.PagePadding + extraMarginLeft,
marginRight: StyleConstants.Spacing.Global.PagePadding + extraMarginRight marginRight: StyleConstants.Spacing.Global.PagePadding + extraMarginRight

View File

@ -8,9 +8,10 @@ export interface Props {
width: number width: number
height: number height: number
margin?: number margin?: number
color?: string
} }
const Sparkline: React.FC<Props> = ({ data, width, height, margin = 0 }) => { const Sparkline: React.FC<Props> = ({ data, width, height, margin = 0, color }) => {
const { colors } = useTheme() const { colors } = useTheme()
const dataToPoints = ({ const dataToPoints = ({
@ -70,10 +71,10 @@ const Sparkline: React.FC<Props> = ({ data, width, height, margin = 0 }) => {
return ( return (
<Svg height={height} width={width} style={{ marginRight: margin }} fill='none'> <Svg height={height} width={width} style={{ marginRight: margin }} fill='none'>
<G> <G>
<Path d={'M' + fillPoints.join(' ')} fill={colors.blue} fillOpacity={0.1} /> <Path d={'M' + fillPoints.join(' ')} fill={color || colors.blue} fillOpacity={0.1} />
<Path <Path
d={'M' + linePoints.join(' ')} d={'M' + linePoints.join(' ')}
stroke={colors.blue} stroke={color || colors.blue}
strokeWidth={1} strokeWidth={1}
strokeLinejoin='round' strokeLinejoin='round'
strokeLinecap='round' strokeLinecap='round'

View File

@ -1,6 +1,3 @@
import menuInstance from '@components/contextMenu/instance'
import menuShare from '@components/contextMenu/share'
import menuStatus from '@components/contextMenu/status'
import TimelineActioned from '@components/Timeline/Shared/Actioned' import TimelineActioned from '@components/Timeline/Shared/Actioned'
import TimelineActions from '@components/Timeline/Shared/Actions' import TimelineActions from '@components/Timeline/Shared/Actions'
import TimelineAttachment from '@components/Timeline/Shared/Attachment' import TimelineAttachment from '@components/Timeline/Shared/Attachment'
@ -19,9 +16,8 @@ import { usePreferencesQuery } from '@utils/queryHooks/preferences'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import React, { Fragment, useRef, useState } from 'react' import React, { useRef, useState } from 'react'
import { Pressable, StyleProp, View, ViewStyle } from 'react-native' import { Pressable, StyleProp, View, ViewStyle } from 'react-native'
import * as ContextMenu from 'zeego/context-menu'
import StatusContext from './Shared/Context' import StatusContext from './Shared/Context'
import TimelineFeedback from './Shared/Feedback' import TimelineFeedback from './Shared/Feedback'
import TimelineFiltered, { FilteredProps, shouldFilter } from './Shared/Filtered' import TimelineFiltered, { FilteredProps, shouldFilter } from './Shared/Filtered'
@ -126,15 +122,6 @@ const TimelineDefault: React.FC<Props> = ({
</> </>
) )
const mShare = menuShare({
visibility: status.visibility,
type: 'status',
url: status.url || status.uri,
rawContent
})
const mStatus = menuStatus({ status, queryKey })
const mInstance = menuInstance({ status, queryKey })
if (!isMyAccount) { if (!isMyAccount) {
let filterResults: FilteredProps['filterResults'] = [] let filterResults: FilteredProps['filterResults'] = []
const [filterRevealed, setFilterRevealed] = useState(false) const [filterRevealed, setFilterRevealed] = useState(false)
@ -183,67 +170,14 @@ const TimelineDefault: React.FC<Props> = ({
<View style={mainStyle}>{main()}</View> <View style={mainStyle}>{main()}</View>
) : ( ) : (
<> <>
<ContextMenu.Root> <Pressable
<ContextMenu.Trigger> accessible={highlighted ? false : true}
<Pressable style={mainStyle}
accessible={highlighted ? false : true} disabled={highlighted}
style={mainStyle} onPress={() => navigation.push('Tab-Shared-Toot', { toot: status })}
disabled={highlighted} onLongPress={() => {}}
onPress={() => navigation.push('Tab-Shared-Toot', { toot: status })} children={main()}
onLongPress={() => {}} />
children={main()}
/>
</ContextMenu.Trigger>
<ContextMenu.Content>
{[mShare, mStatus, mInstance].map((menu, i) => (
<Fragment key={i}>
{menu.map((group, index) => (
<ContextMenu.Group key={index}>
{group.map(item => {
switch (item.type) {
case 'item':
return (
<ContextMenu.Item key={item.key} {...item.props}>
<ContextMenu.ItemTitle children={item.title} />
{item.icon ? (
<ContextMenu.ItemIcon ios={{ name: item.icon }} />
) : null}
</ContextMenu.Item>
)
case 'sub':
return (
// @ts-ignore
<ContextMenu.Sub key={item.key}>
<ContextMenu.SubTrigger
key={item.trigger.key}
{...item.trigger.props}
>
<ContextMenu.ItemTitle children={item.trigger.title} />
{item.trigger.icon ? (
<ContextMenu.ItemIcon ios={{ name: item.trigger.icon }} />
) : null}
</ContextMenu.SubTrigger>
<ContextMenu.SubContent>
{item.items.map(sub => (
<ContextMenu.Item key={sub.key} {...sub.props}>
<ContextMenu.ItemTitle children={sub.title} />
{sub.icon ? (
<ContextMenu.ItemIcon ios={{ name: sub.icon }} />
) : null}
</ContextMenu.Item>
))}
</ContextMenu.SubContent>
</ContextMenu.Sub>
)
}
})}
</ContextMenu.Group>
))}
</Fragment>
))}
</ContextMenu.Content>
</ContextMenu.Root>
<TimelineHeaderAndroid /> <TimelineHeaderAndroid />
</> </>
)} )}

View File

@ -1,6 +1,3 @@
import menuInstance from '@components/contextMenu/instance'
import menuShare from '@components/contextMenu/share'
import menuStatus from '@components/contextMenu/status'
import TimelineActioned from '@components/Timeline/Shared/Actioned' import TimelineActioned from '@components/Timeline/Shared/Actioned'
import TimelineActions from '@components/Timeline/Shared/Actions' import TimelineActions from '@components/Timeline/Shared/Actions'
import TimelineAttachment from '@components/Timeline/Shared/Attachment' import TimelineAttachment from '@components/Timeline/Shared/Attachment'
@ -18,9 +15,8 @@ import { usePreferencesQuery } from '@utils/queryHooks/preferences'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline' import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import React, { Fragment, useState } from 'react' import React, { useState } from 'react'
import { Pressable, View } from 'react-native' import { Pressable, View } from 'react-native'
import * as ContextMenu from 'zeego/context-menu'
import StatusContext from './Shared/Context' import StatusContext from './Shared/Context'
import TimelineFiltered, { FilteredProps, shouldFilter } from './Shared/Filtered' import TimelineFiltered, { FilteredProps, shouldFilter } from './Shared/Filtered'
import TimelineFullConversation from './Shared/FullConversation' import TimelineFullConversation from './Shared/FullConversation'
@ -66,14 +62,16 @@ const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
<View <View
style={{ style={{
opacity: opacity: [
notification.type === 'follow' || 'follow',
notification.type === 'follow_request' || 'follow_request',
notification.type === 'mention' || 'mention',
notification.type === 'status' || 'status',
notification.type === 'admin.sign_up' 'poll',
? 1 'admin.sign_up'
: 0.5 ].includes(notification.type)
? 1
: 0.5
}} }}
> >
<View style={{ flex: 1, width: '100%', flexDirection: 'row' }}> <View style={{ flex: 1, width: '100%', flexDirection: 'row' }}>
@ -100,14 +98,6 @@ const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
) )
} }
const mShare = menuShare({
visibility: notification.status?.visibility,
type: 'status',
url: notification.status?.url || notification.status?.uri
})
const mStatus = menuStatus({ status: notification.status, queryKey })
const mInstance = menuInstance({ status: notification.status, queryKey })
if (!isMyAccount) { if (!isMyAccount) {
let filterResults: FilteredProps['filterResults'] = [] let filterResults: FilteredProps['filterResults'] = []
const [filterRevealed, setFilterRevealed] = useState(false) const [filterRevealed, setFilterRevealed] = useState(false)
@ -143,67 +133,18 @@ const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
spoilerHidden spoilerHidden
}} }}
> >
<ContextMenu.Root> <Pressable
<ContextMenu.Trigger> style={{
<Pressable padding: StyleConstants.Spacing.Global.PagePadding,
style={{ backgroundColor: colors.backgroundDefault,
padding: StyleConstants.Spacing.Global.PagePadding, paddingBottom: notification.status ? 0 : StyleConstants.Spacing.Global.PagePadding
backgroundColor: colors.backgroundDefault, }}
paddingBottom: notification.status ? 0 : StyleConstants.Spacing.Global.PagePadding onPress={() =>
}} notification.status && navigation.push('Tab-Shared-Toot', { toot: notification.status })
onPress={() => }
notification.status && onLongPress={() => {}}
navigation.push('Tab-Shared-Toot', { toot: notification.status }) children={main()}
} />
onLongPress={() => {}}
children={main()}
/>
</ContextMenu.Trigger>
<ContextMenu.Content>
{[mShare, mStatus, mInstance].map((menu, i) => (
<Fragment key={i}>
{menu.map((group, index) => (
<ContextMenu.Group key={index}>
{group.map(item => {
switch (item.type) {
case 'item':
return (
<ContextMenu.Item key={item.key} {...item.props}>
<ContextMenu.ItemTitle children={item.title} />
{item.icon ? <ContextMenu.ItemIcon ios={{ name: item.icon }} /> : null}
</ContextMenu.Item>
)
case 'sub':
return (
// @ts-ignore
<ContextMenu.Sub key={item.key}>
<ContextMenu.SubTrigger key={item.trigger.key} {...item.trigger.props}>
<ContextMenu.ItemTitle children={item.trigger.title} />
{item.trigger.icon ? (
<ContextMenu.ItemIcon ios={{ name: item.trigger.icon }} />
) : null}
</ContextMenu.SubTrigger>
<ContextMenu.SubContent>
{item.items.map(sub => (
<ContextMenu.Item key={sub.key} {...sub.props}>
<ContextMenu.ItemTitle children={sub.title} />
{sub.icon ? (
<ContextMenu.ItemIcon ios={{ name: sub.icon }} />
) : null}
</ContextMenu.Item>
))}
</ContextMenu.SubContent>
</ContextMenu.Sub>
)
}
})}
</ContextMenu.Group>
))}
</Fragment>
))}
</ContextMenu.Content>
</ContextMenu.Root>
<TimelineHeaderAndroid /> <TimelineHeaderAndroid />
</StatusContext.Provider> </StatusContext.Provider>
) )

View File

@ -218,6 +218,7 @@ const TimelineRefresh: React.FC<Props> = ({
} }
isFetchingPrev.value = false isFetchingPrev.value = false
}) })
.catch(() => (isFetchingPrev.value = false))
} }
const runFetchLatest = async () => { const runFetchLatest = async () => {

View File

@ -10,6 +10,7 @@ import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Pressable, StyleSheet, View } from 'react-native' import { Pressable, StyleSheet, View } from 'react-native'
import StatusContext from './Context' import StatusContext from './Context'
import GracefullyImage from '@components/GracefullyImage'
export interface Props { export interface Props {
action: Mastodon.Notification['type'] | 'reblog' | 'pinned' action: Mastodon.Notification['type'] | 'reblog' | 'pinned'
@ -34,11 +35,30 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
content={content} content={content}
emojis={account.emojis} emojis={account.emojis}
size='S' size='S'
style={{ color: action === 'admin.report' ? colors.red : colors.primaryDefault }} style={{ flex: 1, color: action === 'admin.report' ? colors.red : colors.primaryDefault }}
/> />
) )
const onPress = () => navigation.push('Tab-Shared-Account', { account }) const onPress = () => navigation.push('Tab-Shared-Account', { account })
const miniAvatar = (
<GracefullyImage
sources={{
default: { uri: account.avatar },
static: { uri: account.avatar_static }
}}
dimension={{
width: StyleConstants.Avatar.XS / 1.5,
height: StyleConstants.Avatar.XS / 1.5
}}
style={{
borderRadius: 99,
overflow: 'hidden',
marginRight: StyleConstants.Spacing.S
}}
dim
withoutTransition
/>
)
const children = () => { const children = () => {
switch (action) { switch (action) {
@ -63,7 +83,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
color={iconColor} color={iconColor}
style={styles.icon} style={styles.icon}
/> />
<Pressable onPress={onPress}> <Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
{miniAvatar}
{content(t('shared.actioned.favourite', { name }))} {content(t('shared.actioned.favourite', { name }))}
</Pressable> </Pressable>
</> </>
@ -77,7 +98,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
color={iconColor} color={iconColor}
style={styles.icon} style={styles.icon}
/> />
<Pressable onPress={onPress}> <Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
{miniAvatar}
{content(t('shared.actioned.follow', { name }))} {content(t('shared.actioned.follow', { name }))}
</Pressable> </Pressable>
</> </>
@ -91,7 +113,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
color={iconColor} color={iconColor}
style={styles.icon} style={styles.icon}
/> />
<Pressable onPress={onPress}> <Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
{miniAvatar}
{content(t('shared.actioned.follow_request', { name }))} {content(t('shared.actioned.follow_request', { name }))}
</Pressable> </Pressable>
</> </>
@ -118,7 +141,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
color={iconColor} color={iconColor}
style={styles.icon} style={styles.icon}
/> />
<Pressable onPress={onPress}> <Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
{!myself ? miniAvatar : null}
{content( {content(
isNotification isNotification
? t('shared.actioned.reblog.notification', { name }) ? t('shared.actioned.reblog.notification', { name })
@ -138,7 +162,8 @@ const TimelineActioned: React.FC<Props> = ({ action, isNotification, ...rest })
color={iconColor} color={iconColor}
style={styles.icon} style={styles.icon}
/> />
<Pressable onPress={onPress}> <Pressable onPress={onPress} style={{ flexDirection: 'row', alignItems: 'center' }}>
{miniAvatar}
{content(t('shared.actioned.status', { name }))} {content(t('shared.actioned.status', { name }))}
</Pressable> </Pressable>
</> </>

View File

@ -1,147 +1,195 @@
import GracefullyImage from '@components/GracefullyImage' import GracefullyImage from '@components/GracefullyImage'
import openLink from '@components/openLink'
import CustomText from '@components/Text' import CustomText from '@components/Text'
import openLink from '@components/openLink'
import { useNeodbQuery } from '@utils/queryHooks/neodb' import { useNeodbQuery } from '@utils/queryHooks/neodb'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { StyleConstants } from '@utils/styles/constants'
import * as Linking from 'expo-linking' import * as Linking from 'expo-linking'
import { useState } from 'react' import { useContext, useState } from 'react'
import { Pressable, View } from 'react-native' import { Pressable, View } from 'react-native'
import StatusContext from '../Context'
import { Rating } from './Rating' import { Rating } from './Rating'
export type Props = { export const CardNeodb: React.FC = () => {
card: Mastodon.Card const { status } = useContext(StatusContext)
}
export const CardNeodb: React.FC<Props> = ({ card }) => {
const { colors } = useTheme() const { colors } = useTheme()
const segments = Linking.parse(card.url).path?.split('/') const path = Linking.parse(status?.card?.url || '').path
if (!segments || !(segments[0] === 'movie' || segments[0] === 'book' || segments[0] === 'tv')) if (!path) return null
const segments = path?.split('/')
if (
!segments ||
!['movie', 'book', 'tv', 'game', 'album', 'podcast', 'performance'].includes(segments[0])
)
return null return null
const [headingLines, setHeadingLines] = useState(3) const [headingLines, setHeadingLines] = useState<number>()
const { data } = useNeodbQuery({ path: `${segments[0]}/${segments[1]}` }) const { data } = useNeodbQuery({ path })
if (!data) return null if (!data) return null
const pressableProps = { const Content = ({ heading, details }: { heading: string[]; details: string[] }) => (
style: { <Pressable
marginTop: StyleConstants.Spacing.M, style={{
backgroundColor: colors.shimmerDefault, marginTop: StyleConstants.Spacing.M,
borderRadius: StyleConstants.BorderRadius, backgroundColor: colors.shimmerDefault,
padding: StyleConstants.Spacing.S, borderRadius: StyleConstants.BorderRadius,
flexDirection: 'row' as 'row' padding: StyleConstants.Spacing.S,
}, flexDirection: 'row'
onPress: () => openLink(card.url)
}
const contentProps = { style: { flex: 1, gap: StyleConstants.Spacing.S } }
const itemImage = data.cover_image_url ? (
<GracefullyImage
sources={{ default: { uri: data.cover_image_url } }}
dimension={{
width: StyleConstants.Font.LineHeight.M * 4,
height: StyleConstants.Font.LineHeight.M * 5
}} }}
style={{ marginRight: StyleConstants.Spacing.S }} onPress={() => status?.card?.url && openLink(status.card.url)}
imageStyle={{ borderRadius: StyleConstants.BorderRadius / 2 }} >
dim {data.cover_image_url ? (
/> <GracefullyImage
) : null sources={{
const itemHeading = (value: string) => ( default: {
<CustomText uri: data.cover_image_url.startsWith('/')
fontStyle='S' ? `https://neodb.social${data.cover_image_url}`
fontWeight='Bold' : data.cover_image_url
style={{ color: colors.primaryDefault }} }
numberOfLines={3} }}
children={value} dimension={{
onTextLayout={({ nativeEvent }) => setHeadingLines(nativeEvent.lines.length)} width: StyleConstants.Font.LineHeight.M * 4,
/> height: StyleConstants.Font.LineHeight.M * 5
) }}
const itemDetails = (value: string) => ( style={{ marginRight: StyleConstants.Spacing.S }}
<CustomText imageStyle={{ borderRadius: StyleConstants.BorderRadius / 2 }}
fontStyle='S' dim
style={{ color: colors.secondary }} />
numberOfLines={4 - headingLines} ) : null}
children={value} <View style={{ flex: 1, gap: StyleConstants.Spacing.S, justifyContent: 'space-between' }}>
/> <View style={{ gap: StyleConstants.Spacing.S }}>
<CustomText
fontStyle='S'
fontWeight='Bold'
style={{ color: colors.primaryDefault }}
numberOfLines={3}
onTextLayout={({ nativeEvent }) =>
!headingLines && setHeadingLines(nativeEvent.lines.length)
}
children={heading.filter(d => d).join(' ')}
/>
<Rating rating={data.rating / 2} />
</View>
<CustomText
fontStyle='S'
style={{ color: colors.secondary }}
numberOfLines={4 - (headingLines || 3)}
children={details.filter(d => d).join(' / ')}
/>
</View>
</Pressable>
) )
switch (segments[0]) { switch (segments[0]) {
case 'movie': case 'movie':
return ( return (
<Pressable {...pressableProps}> <Content
{itemImage} heading={[data.title, data.orig_title, data.year ? `(${data.year})` : null]}
<View {...contentProps}> details={[
{itemHeading( data.duration
[data.title, data.orig_title, data.year ? `(${data.year})` : null] ? parseInt(data.duration).toString() === data.duration
.filter(d => d) ? `${data.duration}分钟`
.join(' ') : data.duration
)} : null,
<Rating rating={data.rating / 2} /> data.area?.join(' '),
{itemDetails( data.genre?.join(' '),
[ data.director?.join(' ')
data.duration ]}
? parseInt(data.duration).toString() === data.duration />
? `${data.duration}分钟`
: data.duration
: null,
data.area?.join(' '),
data.genre?.join(' '),
data.director?.join(' ')
]
.filter(d => d)
.join(' / ')
)}
</View>
</Pressable>
) )
case 'book': case 'book':
return ( return (
<Pressable {...pressableProps}> <Content
{itemImage} heading={[data.title]}
<View {...contentProps}> details={[
{itemHeading(data.title)} data.author?.join(' '),
<Rating rating={data.rating / 2} /> data.pages ? `${data.pages}` : null,
{itemDetails( data.language,
[ data.pub_house
data.author?.join(' '), ]}
data.pages ? `${data.pages}` : null, />
data.language,
data.pub_house
]
.filter(d => d)
.join(' / ')
)}
</View>
</Pressable>
) )
case 'tv': case 'tv':
if (segments[1] === 'season') {
return (
<Content
heading={[data.title, data.orig_title, data.year ? `(${data.year})` : null]}
details={[
data.season_number ? `${data.season_number}` : null,
data.episode_count ? `${data.episode_count}` : null,
data.area?.join(' '),
data.genre?.join(' '),
data.director?.join(' ')
]}
/>
)
} else {
return (
<Content
heading={[data.title, data.orig_title, data.year ? `(${data.year})` : null]}
details={[
data.season_count ? `${data.season_count}` : null,
data.area?.join(' '),
data.genre?.join(' '),
data.director?.join(' ')
]}
/>
)
}
case 'game':
return ( return (
<Pressable {...pressableProps}> <Content
{itemImage} heading={[data.title]}
<View {...contentProps}> details={[
{itemHeading( data.genre?.join(' '),
[data.title, data.orig_title, data.year ? `(${data.year})` : null] data.developer?.join(' '),
.filter(d => d) data.platform?.join(' '),
.join(' ') data.release_date
)} ]}
<Rating rating={data.rating / 2} /> />
{itemDetails(
[
data.season_count ? `${data.season_count}` : null,
data.area?.join(' '),
data.genre?.join(' '),
data.director?.join(' ')
]
.filter(d => d)
.join(' / ')
)}
</View>
</Pressable>
) )
case 'album':
return (
<Content
heading={[data.title]}
details={[
data.artist.join(' '),
data.release_date,
data.duration,
data.genre.join(' '),
data.company.join(' ')
]}
/>
)
case 'podcast':
return (
<Content heading={[data.title]} details={[data.hosts.join(' '), data.genre.join(' ')]} />
)
case 'performance':
if (segments[1] === 'production') {
return (
<Content
heading={[data.display_title]}
details={[
data.opening_date,
data.director.join(' '),
data.playwright.join(' '),
data.composer.join(' ')
]}
/>
)
} else {
return (
<Content
heading={[data.title, data.orig_title]}
details={[data.genre.join(' '), data.playwright.join(' '), data.director.join(' ')]}
/>
)
}
default: default:
return null return null
} }

View File

@ -1,15 +1,16 @@
import ComponentAccount from '@components/Account' import ComponentAccount from '@components/Account'
import GracefullyImage from '@components/GracefullyImage' import GracefullyImage from '@components/GracefullyImage'
import openLink from '@components/openLink'
import CustomText from '@components/Text' import CustomText from '@components/Text'
import openLink from '@components/openLink'
import { useNavigation } from '@react-navigation/native' import { useNavigation } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack' import { StackNavigationProp } from '@react-navigation/stack'
import { isDevelopment } from '@utils/helpers/checkEnvironment'
import { urlMatcher } from '@utils/helpers/urlMatcher' import { urlMatcher } from '@utils/helpers/urlMatcher'
import { TabLocalStackParamList } from '@utils/navigation/navigators' import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { useAccountQuery } from '@utils/queryHooks/account' import { useAccountQuery } from '@utils/queryHooks/account'
import { useStatusQuery } from '@utils/queryHooks/status' import { useStatusQuery } from '@utils/queryHooks/status'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { StyleConstants } from '@utils/styles/constants'
import React, { useContext, useEffect, useState } from 'react' import React, { useContext, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Pressable, View } from 'react-native' import { Pressable, View } from 'react-native'
@ -17,16 +18,21 @@ import TimelineDefault from '../../Default'
import StatusContext from '../Context' import StatusContext from '../Context'
import { CardNeodb } from './Neodb' import { CardNeodb } from './Neodb'
const CARD_URL_BLACKLISTS = ['weibo.com', 'weibo.cn']
const TimelineCard: React.FC = () => { const TimelineCard: React.FC = () => {
const { status, spoilerHidden, disableDetails, inThread } = useContext(StatusContext) const { status, spoilerHidden, disableDetails, inThread } = useContext(StatusContext)
if (!status || !status.card) return null if (!status || !status.card) return null
if (CARD_URL_BLACKLISTS.find(domain => status.card?.url.includes(`${domain}/`))) return null
const { i18n } = useTranslation() const { i18n } = useTranslation()
if ( if (
status.card.url.includes('://neodb.social/') && (status.card.url.includes('://neodb.social/') &&
i18n.language.toLowerCase().startsWith('zh-hans') i18n.language.toLowerCase().startsWith('zh-hans')) ||
isDevelopment
) { ) {
return <CardNeodb card={status.card} /> return <CardNeodb />
} }
const { colors } = useTheme() const { colors } = useTheme()

View File

@ -36,6 +36,7 @@ const TimelineContent: React.FC<Props> = ({ notificationOwnToot = false, setSpoi
adaptiveSize adaptiveSize
numberOfLines={999} numberOfLines={999}
color={suppressSpoiler ? colors.disabled : undefined} color={suppressSpoiler ? colors.disabled : undefined}
selectable
/> />
{inThread ? ( {inThread ? (
<CustomText <CustomText
@ -62,6 +63,7 @@ const TimelineContent: React.FC<Props> = ({ notificationOwnToot = false, setSpoi
} }
expandHint={t('shared.content.expandHint')} expandHint={t('shared.content.expandHint')}
setSpoilerExpanded={setSpoilerExpanded} setSpoilerExpanded={setSpoilerExpanded}
selectable
/> />
</> </>
) : ( ) : (
@ -70,6 +72,7 @@ const TimelineContent: React.FC<Props> = ({ notificationOwnToot = false, setSpoi
size={highlighted ? 'L' : 'M'} size={highlighted ? 'L' : 'M'}
adaptiveSize adaptiveSize
numberOfLines={highlighted || inThread ? 999 : notificationOwnToot ? 2 : undefined} numberOfLines={highlighted || inThread ? 999 : notificationOwnToot ? 2 : undefined}
selectable
/> />
)} )}
</View> </View>

View File

@ -39,6 +39,7 @@ const TimelineHeaderAndroid: React.FC = () => {
<View <View
style={{ style={{
padding: StyleConstants.Spacing.L, padding: StyleConstants.Spacing.L,
paddingBottom: StyleConstants.Spacing.S,
backgroundColor: colors.backgroundDefault backgroundColor: colors.backgroundDefault
}} }}
> >

View File

@ -1,4 +1,5 @@
import menuAccount from '@components/contextMenu/account' import menuAccount from '@components/contextMenu/account'
import menuInstance from '@components/contextMenu/instance'
import menuShare from '@components/contextMenu/share' import menuShare from '@components/contextMenu/share'
import menuStatus from '@components/contextMenu/status' import menuStatus from '@components/contextMenu/status'
import Icon from '@components/Icon' import Icon from '@components/Icon'
@ -17,7 +18,8 @@ import HeaderSharedReplies from './HeaderShared/Replies'
import HeaderSharedVisibility from './HeaderShared/Visibility' import HeaderSharedVisibility from './HeaderShared/Visibility'
const TimelineHeaderDefault: React.FC = () => { const TimelineHeaderDefault: React.FC = () => {
const { queryKey, status, disableDetails, rawContent, isRemote } = useContext(StatusContext) const { queryKey, status, disableDetails, rawContent, isRemote, highlighted } =
useContext(StatusContext)
if (!status) return null if (!status) return null
const { colors } = useTheme() const { colors } = useTheme()
@ -37,6 +39,7 @@ const TimelineHeaderDefault: React.FC = () => {
...(status && { status }) ...(status && { status })
}) })
const mStatus = menuStatus({ status, queryKey }) const mStatus = menuStatus({ status, queryKey })
const mInstance = highlighted ? menuInstance({ status, queryKey }) : []
return ( return (
<View style={{ flex: 1, flexDirection: 'row' }}> <View style={{ flex: 1, flexDirection: 'row' }}>
@ -87,7 +90,7 @@ const TimelineHeaderDefault: React.FC = () => {
</DropdownMenu.Trigger> </DropdownMenu.Trigger>
<DropdownMenu.Content> <DropdownMenu.Content>
{[mShare, mAccount, mStatus].map((menu, i) => ( {[mShare, mAccount, mStatus, mInstance].map((menu, i) => (
<Fragment key={i}> <Fragment key={i}>
{menu.map((group, index) => ( {menu.map((group, index) => (
<DropdownMenu.Group key={index}> <DropdownMenu.Group key={index}>

View File

@ -1,3 +1,4 @@
import Icon from '@components/Icon'
import ComponentSeparator from '@components/Separator' import ComponentSeparator from '@components/Separator'
import CustomText from '@components/Text' import CustomText from '@components/Text'
import TimelineDefault from '@components/Timeline/Default' import TimelineDefault from '@components/Timeline/Default'
@ -10,12 +11,20 @@ import {
setAccountStorage, setAccountStorage,
useGlobalStorageListener useGlobalStorageListener
} from '@utils/storage/actions' } from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { StyleConstants } from '@utils/styles/constants'
import { throttle } from 'lodash' import { throttle } from 'lodash'
import React, { RefObject, useCallback, useEffect, useRef, useState } from 'react' import React, { RefObject, useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { FlatList, FlatListProps, Platform, RefreshControl } from 'react-native' import {
FlatList,
FlatListProps,
Platform,
Pressable,
RefreshControl,
StyleProp,
ViewStyle
} from 'react-native'
import Animated, { import Animated, {
Easing, Easing,
runOnJS, runOnJS,
@ -127,6 +136,27 @@ const Timeline: React.FC<Props> = ({
transform: [{ translateY: fetchedNoticeTop.value }] transform: [{ translateY: fetchedNoticeTop.value }]
})) }))
const refetchedNoticeBottom = useDerivedValue(() => {
if (firstLoad.value) {
return withSequence(
withTiming(0),
withDelay(
3000,
withTiming(fetchedNoticeHeight.value + 32, { easing: Easing.out(Easing.ease) })
)
)
} else {
return fetchedNoticeHeight.value + 32
}
}, [])
const refetchedNoticeAnimate = useAnimatedStyle(() => ({
transform: [
{
translateY: refetchedNoticeBottom.value
}
]
}))
const scrollY = useSharedValue(0) const scrollY = useSharedValue(0)
const fetchingType = useSharedValue<0 | 1 | 2>(0) const fetchingType = useSharedValue<0 | 1 | 2>(0)
@ -169,10 +199,9 @@ const Timeline: React.FC<Props> = ({
throttle(() => { throttle(() => {
if (readMarker) { if (readMarker) {
const currentMarker = getAccountStorage.string(readMarker) || '0' const currentMarker = getAccountStorage.string(readMarker) || '0'
// setAccountStorage([{ key: readMarker, value: '108425743226508521' }])
if (latestMarker.current > currentMarker) { if (latestMarker.current > currentMarker) {
setAccountStorage([{ key: readMarker, value: latestMarker.current }]) setAccountStorage([{ key: readMarker, value: latestMarker.current }])
} else {
// setAccountStorage([{ key: readMarker, value: '105250709762254246' }])
} }
} }
}, 1000 * 15), }, 1000 * 15),
@ -242,6 +271,18 @@ const Timeline: React.FC<Props> = ({
flRef.current?.scrollToOffset({ offset: 0, animated: false }) flRef.current?.scrollToOffset({ offset: 0, animated: false })
) )
const noticeDefaults: StyleProp<Animated.AnimateStyle<StyleProp<ViewStyle>>> = {
position: 'absolute',
alignSelf: 'center',
borderRadius: 99,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: colors.backgroundDefault,
shadowColor: colors.primaryDefault,
shadowOffset: { width: 0, height: 0 },
shadowOpacity: theme === 'light' ? 0.16 : 0.24
}
return ( return (
<> <>
<TimelineRefresh <TimelineRefresh
@ -286,42 +327,78 @@ const Timeline: React.FC<Props> = ({
{...customProps} {...customProps}
/> />
{!disableRefresh ? ( {!disableRefresh ? (
<Animated.View <>
style={[ <Animated.View
{ style={[
position: 'absolute', {
alignSelf: 'center', top: -fetchedNoticeHeight.value - 16,
top: -fetchedNoticeHeight.value - 16, paddingVertical: StyleConstants.Spacing.S,
paddingVertical: StyleConstants.Spacing.S, paddingHorizontal: StyleConstants.Spacing.M,
paddingHorizontal: StyleConstants.Spacing.M, ...noticeDefaults
backgroundColor: colors.backgroundDefault, },
shadowColor: colors.primaryDefault, fetchedNoticeAnimate
shadowOffset: { width: 0, height: 0 }, ]}
shadowOpacity: theme === 'light' ? 0.16 : 0.24, onLayout={({
borderRadius: 99, nativeEvent: {
justifyContent: 'center', layout: { height }
alignItems: 'center' }
}, }) => (fetchedNoticeHeight.value = height)}
fetchedNoticeAnimate >
]} <CustomText
onLayout={({ fontStyle='S'
nativeEvent: { style={{ color: colors.primaryDefault }}
layout: { height } children={
} fetchedCount !== null
}) => (fetchedNoticeHeight.value = height)} ? fetchedCount > 0
> ? t('refresh.fetched.found', { count: fetchedCount })
<CustomText : t('refresh.fetched.none')
fontStyle='S' : t('refresh.fetching')
style={{ color: colors.primaryDefault }} }
children={ />
fetchedCount !== null </Animated.View>
? fetchedCount > 0 {readMarker ? (
? t('refresh.fetched.found', { count: fetchedCount }) <Animated.View
: t('refresh.fetched.none') style={[
: t('refresh.fetching') {
} bottom: 16,
/> borderColor: colors.primaryDefault,
</Animated.View> borderWidth: 0.5,
...noticeDefaults
},
refetchedNoticeAnimate
]}
>
<Pressable
style={{
flexDirection: 'row',
alignItems: 'center',
gap: StyleConstants.Spacing.S,
paddingVertical: StyleConstants.Spacing.S,
paddingHorizontal: StyleConstants.Spacing.M
}}
onPress={async () => {
if (readMarker) {
setAccountStorage([{ key: readMarker, value: undefined }])
}
flRef.current?.scrollToOffset({ offset: 0 })
await refetch()
}}
>
<CustomText
fontStyle='M'
style={{ color: colors.primaryDefault }}
children={t('refresh.refetch')}
/>
<Icon
name='log-in'
color={colors.primaryDefault}
size={StyleConstants.Font.Size.M}
style={{ transform: [{ rotate: '-90deg' }] }}
/>
</Pressable>
</Animated.View>
) : null}
</>
) : null} ) : null}
</> </>
) )

View File

@ -4,6 +4,7 @@ import { useNavigation } from '@react-navigation/native'
import { NativeStackNavigationProp } from '@react-navigation/native-stack' import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { useQueryClient } from '@tanstack/react-query' import { useQueryClient } from '@tanstack/react-query'
import apiInstance from '@utils/api/instance' import apiInstance from '@utils/api/instance'
import { featureCheck } from '@utils/helpers/featureCheck'
import { checkIsMyAccount } from '@utils/helpers/isMyAccount' import { checkIsMyAccount } from '@utils/helpers/isMyAccount'
import { TabSharedStackParamList, useNavState } from '@utils/navigation/navigators' import { TabSharedStackParamList, useNavState } from '@utils/navigation/navigators'
import { useAccountQuery } from '@utils/queryHooks/account' import { useAccountQuery } from '@utils/queryHooks/account'
@ -203,13 +204,22 @@ const menuAccount = ({
type: 'item', type: 'item',
key: 'account-mute', key: 'account-mute',
props: { props: {
onSelect: () => onSelect: () => {
actualAccount && if (actualAccount) {
timelineMutation.mutate({ if (data?.muting !== true) {
type: 'updateAccountProperty', if (featureCheck('mute_duration')) {
id: actualAccount.id, navigation.navigate('Tab-Shared-Mute', { account: actualAccount })
payload: { property: 'mute', currentValue: data?.muting } return
}), }
}
timelineMutation.mutate({
type: 'updateAccountProperty',
id: actualAccount.id,
payload: { property: 'mute', currentValue: data?.muting }
})
}
},
disabled: Platform.OS !== 'android' ? !data || !isFetched : false, disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
destructive: false, destructive: false,
hidden: false hidden: false

View File

@ -8,6 +8,7 @@ import { QueryKeyStatus } from '@utils/queryHooks/status'
import { getGlobalStorage } from '@utils/storage/actions' import { getGlobalStorage } from '@utils/storage/actions'
import * as Linking from 'expo-linking' import * as Linking from 'expo-linking'
import * as WebBrowser from 'expo-web-browser' import * as WebBrowser from 'expo-web-browser'
import { WebBrowserPresentationStyle } from 'expo-web-browser'
const openLink = async (url: string, navigation?: any) => { const openLink = async (url: string, navigation?: any) => {
const handleNavigation = (page: 'Tab-Shared-Toot' | 'Tab-Shared-Account', options: any) => { const handleNavigation = (page: 'Tab-Shared-Toot' | 'Tab-Shared-Account', options: any) => {
@ -74,6 +75,7 @@ const openLink = async (url: string, navigation?: any) => {
default: default:
await WebBrowser.openBrowserAsync(url.trim(), { await WebBrowser.openBrowserAsync(url.trim(), {
dismissButtonStyle: 'close', dismissButtonStyle: 'close',
presentationStyle: WebBrowserPresentationStyle.AUTOMATIC,
enableBarCollapsing: true, enableBarCollapsing: true,
...(await browserPackage()) ...(await browserPackage())
}).catch(() => Linking.openURL(url.trim())) }).catch(() => Linking.openURL(url.trim()))

View File

@ -11,11 +11,11 @@
}, },
"right": { "right": {
"button": { "button": {
"default": "Допіс", "default": "Апублікаваць",
"conversation": "Асабістае паведамленне", "conversation": "Асабістае паведамленне",
"reply": "Адказаць", "reply": "Адказаць",
"deleteEdit": "Допіс", "deleteEdit": "Апублікаваць",
"edit": "Допіс", "edit": "Апублікаваць",
"share": "Допіс" "share": "Допіс"
}, },
"alert": { "alert": {

View File

@ -387,12 +387,12 @@
"account": { "account": {
"actions": { "actions": {
"accessibilityLabel": "Дзеянні для карыстальніка {{user}}", "accessibilityLabel": "Дзеянні для карыстальніка {{user}}",
"accessibilityHint": "" "accessibilityHint": "Вы можаце ігнараваць, блакіраваць або абагуліць гэтага карыстальніка"
}, },
"followed_by": " падпісаны на вас", "followed_by": " падпісаны на вас",
"privateNote": "", "privateNote": "Задаць прыватную нататку",
"moved": "", "moved": "Карыстальнік перанесены",
"created_at": "", "created_at": "Далучыўся: {{date}}",
"summary": { "summary": {
"statuses_count": "{{count}} допісаў" "statuses_count": "{{count}} допісаў"
}, },
@ -412,11 +412,25 @@
}, },
"filter": { "filter": {
"name": "Дадаць у фільтр", "name": "Дадаць у фільтр",
"existed": "" "existed": "Існаваў у гэтых фільтрах"
}, },
"history": { "history": {
"name": "Гісторыя рэдагавання" "name": "Гісторыя рэдагавання"
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "Бестэрмінова",
"1800": "30 хвілін",
"3600": "1 гадзіна",
"86400": "1 дзень",
"604800": "1 тыдзень"
}
},
"report": { "report": {
"name": "Паскардзіцца на {{acct}}", "name": "Паскардзіцца на {{acct}}",
"report": "Скарга", "report": "Скарга",
@ -467,8 +481,8 @@
"toot": { "toot": {
"name": "Абмеркаванні", "name": "Абмеркаванні",
"remoteFetch": { "remoteFetch": {
"title": "", "title": "Змяшчае аддаленае змесціва",
"message": "" "message": "Федэратыўны кантэнт не заўсёды даступны на лакальным серверы. Гэты кантэнт атрымліваецца з аддаленага сервера і мае пазнаку. Вы можаце ўзаемадзейнічаць з гэтым кантэнтам як звычайна."
} }
}, },
"users": { "users": {

View File

@ -153,13 +153,13 @@
"refresh": "Actualitza" "refresh": "Actualitza"
}, },
"count": { "count": {
"voters_one": "{{count}} usuari ha votat", "voters_one": "{{count}} vot",
"voters_other": "{{count}} usuaris han votat", "voters_other": "{{count}} vots",
"votes_one": "{{count}} vot", "votes_one": "{{count}} vot",
"votes_other": "{{count}} vots" "votes_other": "{{count}} vots"
}, },
"expiration": { "expiration": {
"expired": "Votació finalitzada", "expired": "Finalitzada",
"until": "Finalitza <0 />" "until": "Finalitza <0 />"
} }
} }

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Edita l'historial" "name": "Edita l'historial"
}, },
"mute": {
"name": "Silencia {{acct}}",
"mute": "Silencia",
"description": "Amaga publicacions i mencions d'aquest usuari, però encara podrà veure les teves publicacions i seguir-te.",
"notification": "També amaga notificacions d'aquest usuari",
"duration": {
"heading": "D'una durada",
"0": "Indefinida",
"1800": "30 minuts",
"3600": "1 hora",
"86400": "1 dia",
"604800": "1 setmana"
}
},
"report": { "report": {
"name": "Denúncia a {{acct}}", "name": "Denúncia a {{acct}}",
"report": "Denúncia", "report": "Denúncia",

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "" "name": ""
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "",
"1800": "",
"3600": "",
"86400": "",
"604800": ""
}
},
"report": { "report": {
"name": "", "name": "",
"report": "", "report": "",

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Bearbeitungsverlauf" "name": "Bearbeitungsverlauf"
}, },
"mute": {
"name": "@{{acct}} stummschalten",
"mute": "Stummschalten",
"description": "Verstecke Tröts des Users und solche, in denen das Konto erwähnt wird. Die Person wird weiterhin deine Beiträge lesen und dir folgen können.",
"notification": "Benachrichtigungen dieses Profils ebenfalls ausblenden",
"duration": {
"heading": "Für die Dauer",
"0": "Dauerhaft",
"1800": "30 Minuten",
"3600": "1 Stunde",
"86400": "1 Tag",
"604800": "1 Woche"
}
},
"report": { "report": {
"name": "{{acct}} melden", "name": "{{acct}} melden",
"report": "Melden", "report": "Melden",

18
src/i18n/el/index.ts Normal file
View File

@ -0,0 +1,18 @@
export default {
common: require('./common'),
screens: require('./screens'),
screenAccountSelection: require('./screens/accountSelection.json'),
screenAnnouncements: require('./screens/announcements'),
screenCompose: require('./screens/compose'),
screenImageViewer: require('./screens/imageViewer'),
screenTabs: require('./screens/tabs'),
componentContextMenu: require('./components/contextMenu'),
componentEmojis: require('./components/emojis'),
componentInstance: require('./components/instance'),
componentMediaSelector: require('./components/mediaSelector'),
componentParse: require('./components/parse'),
componentRelationship: require('./components/relationship'),
componentTimeline: require('./components/timeline')
}

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Ιστορικό επεξεργασίας" "name": "Ιστορικό επεξεργασίας"
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "",
"1800": "",
"3600": "",
"86400": "",
"604800": ""
}
},
"report": { "report": {
"name": "Αναφορά {{acct}}", "name": "Αναφορά {{acct}}",
"report": "Αναφορά", "report": "Αναφορά",

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Edit History" "name": "Edit History"
}, },
"mute": {
"name": "Mute {{acct}}",
"mute": "Mute",
"description": "Hide posts from this user and posts mentioning them, but it will still allow them to see your posts and follow you.",
"notification": "Also hide notifications from this user",
"duration": {
"heading": "For duration",
"0": "Indefinitely",
"1800": "30 minutes",
"3600": "1 hour",
"86400": "1 day",
"604800": "1 week"
}
},
"report": { "report": {
"name": "Report {{acct}}", "name": "Report {{acct}}",
"report": "Report", "report": "Report",

View File

@ -153,13 +153,13 @@
"refresh": "Actualizar" "refresh": "Actualizar"
}, },
"count": { "count": {
"voters_one": "{{count}} usuario ha votado", "voters_one": "{{count}} voto",
"voters_other": "{{count}} usuarios han votado", "voters_other": "{{count}} votos",
"votes_one": "{{count}} voto", "votes_one": "{{count}} voto",
"votes_other": "{{count}} votos" "votes_other": "{{count}} votos"
}, },
"expiration": { "expiration": {
"expired": "Votación expirada", "expired": "Finalizado",
"until": "Expira <0 />" "until": "Expira <0 />"
} }
} }

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Historial de ediciones" "name": "Historial de ediciones"
}, },
"mute": {
"name": "Silenciar a {{acct}}",
"mute": "Silenciar",
"description": "Oculta publicaciones y menciones a este usuario, pero podrá ver tus publicaciones y seguirte.",
"notification": "También oculta notificaciones de este usuario",
"duration": {
"heading": "Durante",
"0": "Indefinidamente",
"1800": "30 minutos",
"3600": "1 hora",
"86400": "1 día",
"604800": "1 semana"
}
},
"report": { "report": {
"name": "Denuncia {{acct}}", "name": "Denuncia {{acct}}",
"report": "Denuncia", "report": "Denuncia",

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "" "name": ""
}, },
"mute": {
"name": "Mututu {{acct}}",
"mute": "Mututu",
"description": "Ezkutatu erabiltzaile honen argitalpenak berari aipatzen dieten argitalpenak, hala ere, berak zure argitalpenak irakurri ahal izango ditu eta zuri jarraitu ere.",
"notification": "Baita ere, ezkutatu erabiltzaile honen jakinarazpenak",
"duration": {
"heading": "Iraupena",
"0": "Mugagabe",
"1800": "30 minutu",
"3600": "Ordu 1",
"86400": "Egun 1",
"604800": "Aste 1"
}
},
"report": { "report": {
"name": "", "name": "",
"report": "", "report": "",

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Modifier l'historique" "name": "Modifier l'historique"
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "",
"1800": "",
"3600": "",
"86400": "",
"604800": ""
}
},
"report": { "report": {
"name": "", "name": "",
"report": "", "report": "",

View File

@ -5,6 +5,7 @@ import { initReactI18next } from 'react-i18next'
import be from './be' import be from './be'
import ca from './ca' import ca from './ca'
import de from './de' import de from './de'
import el from './el'
import en from './en' import en from './en'
import es from './es' import es from './es'
import eu from './eu' import eu from './eu'
@ -29,6 +30,7 @@ import '@formatjs/intl-pluralrules/polyfill'
import '@formatjs/intl-pluralrules/locale-data/be' import '@formatjs/intl-pluralrules/locale-data/be'
import '@formatjs/intl-pluralrules/locale-data/ca' import '@formatjs/intl-pluralrules/locale-data/ca'
import '@formatjs/intl-pluralrules/locale-data/de' import '@formatjs/intl-pluralrules/locale-data/de'
import '@formatjs/intl-pluralrules/locale-data/el'
import '@formatjs/intl-pluralrules/locale-data/en' import '@formatjs/intl-pluralrules/locale-data/en'
import '@formatjs/intl-pluralrules/locale-data/es' import '@formatjs/intl-pluralrules/locale-data/es'
import '@formatjs/intl-pluralrules/locale-data/eu' import '@formatjs/intl-pluralrules/locale-data/eu'
@ -49,6 +51,7 @@ import '@formatjs/intl-numberformat/polyfill'
import '@formatjs/intl-numberformat/locale-data/be' import '@formatjs/intl-numberformat/locale-data/be'
import '@formatjs/intl-numberformat/locale-data/ca' import '@formatjs/intl-numberformat/locale-data/ca'
import '@formatjs/intl-numberformat/locale-data/de' import '@formatjs/intl-numberformat/locale-data/de'
import '@formatjs/intl-numberformat/locale-data/el'
import '@formatjs/intl-numberformat/locale-data/en' import '@formatjs/intl-numberformat/locale-data/en'
import '@formatjs/intl-numberformat/locale-data/es' import '@formatjs/intl-numberformat/locale-data/es'
import '@formatjs/intl-numberformat/locale-data/eu' import '@formatjs/intl-numberformat/locale-data/eu'
@ -71,6 +74,7 @@ import '@formatjs/intl-datetimeformat/add-all-tz'
import '@formatjs/intl-datetimeformat/locale-data/be' import '@formatjs/intl-datetimeformat/locale-data/be'
import '@formatjs/intl-datetimeformat/locale-data/ca' import '@formatjs/intl-datetimeformat/locale-data/ca'
import '@formatjs/intl-datetimeformat/locale-data/de' import '@formatjs/intl-datetimeformat/locale-data/de'
import '@formatjs/intl-datetimeformat/locale-data/el'
import '@formatjs/intl-datetimeformat/locale-data/en' import '@formatjs/intl-datetimeformat/locale-data/en'
import '@formatjs/intl-datetimeformat/locale-data/es' import '@formatjs/intl-datetimeformat/locale-data/es'
import '@formatjs/intl-datetimeformat/locale-data/eu' import '@formatjs/intl-datetimeformat/locale-data/eu'
@ -92,6 +96,7 @@ import '@formatjs/intl-relativetimeformat/polyfill'
import '@formatjs/intl-relativetimeformat/locale-data/be' import '@formatjs/intl-relativetimeformat/locale-data/be'
import '@formatjs/intl-relativetimeformat/locale-data/ca' import '@formatjs/intl-relativetimeformat/locale-data/ca'
import '@formatjs/intl-relativetimeformat/locale-data/de' import '@formatjs/intl-relativetimeformat/locale-data/de'
import '@formatjs/intl-relativetimeformat/locale-data/el'
import '@formatjs/intl-relativetimeformat/locale-data/en' import '@formatjs/intl-relativetimeformat/locale-data/en'
import '@formatjs/intl-relativetimeformat/locale-data/es' import '@formatjs/intl-relativetimeformat/locale-data/es'
import '@formatjs/intl-relativetimeformat/locale-data/eu' import '@formatjs/intl-relativetimeformat/locale-data/eu'
@ -120,6 +125,7 @@ i18n.use(initReactI18next).init({
be, be,
ca, ca,
de, de,
el,
en, en,
es, es,
eu, eu,

View File

@ -5,11 +5,11 @@
"cancel": "Annulla", "cancel": "Annulla",
"discard": "Scarta", "discard": "Scarta",
"continue": "Continua", "continue": "Continua",
"create": "", "create": "Crea",
"delete": "", "delete": "Elimina",
"done": "", "done": "Fatto",
"confirm": "Ho capito", "confirm": "Ho capito",
"add": "" "add": "Aggiungi"
}, },
"customEmoji": { "customEmoji": {
"accessibilityLabel": "Emoji personalizzata {{emoji}}" "accessibilityLabel": "Emoji personalizzata {{emoji}}"

View File

@ -1,13 +1,13 @@
{ {
"server": { "server": {
"textInput": { "textInput": {
"placeholder": "" "placeholder": "Dominio dell'istanza"
}, },
"whitelisted": "", "whitelisted": "Questa potrebbe essere un'istanza nella whitelist nella quale tooot non può accedere ai dati di essa prima di fare il log-in.",
"button": "Accedi", "button": "Accedi",
"information": { "information": {
"name": "Nome", "name": "Nome",
"description": "" "description": "Descrizione"
}, },
"disclaimer": { "disclaimer": {
"base": "Per accedere, verrà aperta una pagina del browser di sistema. I dati di accesso del tuo account sono protetti." "base": "Per accedere, verrà aperta una pagina del browser di sistema. I dati di accesso del tuo account sono protetti."

View File

@ -17,10 +17,10 @@
"refresh": { "refresh": {
"fetchPreviousPage": "Più recenti da qui", "fetchPreviousPage": "Più recenti da qui",
"refetch": "Al più recente", "refetch": "Al più recente",
"fetching": "", "fetching": "Recupero nuovi toot ...",
"fetched": { "fetched": {
"none": "", "none": "Nessun nuovo toot",
"found": "" "found": "{{count}} toot recuperati"
} }
}, },
"shared": { "shared": {

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Cronologia delle modifiche" "name": "Cronologia delle modifiche"
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "",
"1800": "",
"3600": "",
"86400": "",
"604800": ""
}
},
"report": { "report": {
"name": "", "name": "",
"report": "", "report": "",

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "編集履歴" "name": "編集履歴"
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "",
"1800": "",
"3600": "",
"86400": "",
"604800": ""
}
},
"report": { "report": {
"name": "{{acct}} の違反報告", "name": "{{acct}} の違反報告",
"report": "報告", "report": "報告",

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "수정 이력" "name": "수정 이력"
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "",
"1800": "",
"3600": "",
"86400": "",
"604800": ""
}
},
"report": { "report": {
"name": "@{{acct}} 신고", "name": "@{{acct}} 신고",
"report": "신고", "report": "신고",

View File

@ -2,6 +2,7 @@ const LOCALES = {
be: 'Беларуская', be: 'Беларуская',
ca: 'Català', ca: 'Català',
de: 'Deutsch', de: 'Deutsch',
el: 'Ελληνικά',
en: 'English', en: 'English',
es: 'Español', es: 'Español',
eu: 'Euskara', eu: 'Euskara',

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Geschiedenis bewerken" "name": "Geschiedenis bewerken"
}, },
"mute": {
"name": "Demp {{acct}}",
"mute": "Dempen",
"description": "Verberg berichten van deze gebruiker en berichten die hen vermelden, maar het geeft hen nog steeds de mogelijkheid om je posts te zien en je te volgen.",
"notification": "Verberg ook meldingen van deze gebruiker",
"duration": {
"heading": "Voor duur",
"0": "Onbepaalde tijd",
"1800": "30 minuten",
"3600": "1 uur",
"86400": "1 dag",
"604800": "1 week"
}
},
"report": { "report": {
"name": "Rapporteer {{acct}}", "name": "Rapporteer {{acct}}",
"report": "Rapporteer", "report": "Rapporteer",

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Rediger historikk" "name": "Rediger historikk"
}, },
"mute": {
"name": "Demp {{acct}}",
"mute": "Demp",
"description": "Skjul innlegg fra denne brukeren og innleggene som nevner brukeren, men det vil fortsatt la brukeren se dine innlegg og følge deg.",
"notification": "Skjul varsler også for denne brukeren",
"duration": {
"heading": "For varighet",
"0": "På ubestemt tid",
"1800": "30 minutter",
"3600": "Én time",
"86400": "Én dag",
"604800": "én uke"
}
},
"report": { "report": {
"name": "Rapporter {{acct}}", "name": "Rapporter {{acct}}",
"report": "Rapporter", "report": "Rapporter",

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "Historia edycji" "name": "Historia edycji"
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "",
"1800": "",
"3600": "",
"86400": "",
"604800": ""
}
},
"report": { "report": {
"name": "Zgłoś {{acct}}", "name": "Zgłoś {{acct}}",
"report": "Zgłoś", "report": "Zgłoś",

View File

@ -9,7 +9,7 @@
"delete": "Excluir", "delete": "Excluir",
"done": "Concluído", "done": "Concluído",
"confirm": "Confirmar", "confirm": "Confirmar",
"add": "" "add": "Adicionar"
}, },
"customEmoji": { "customEmoji": {
"accessibilityLabel": "Emoji personalizado {{emoji}}" "accessibilityLabel": "Emoji personalizado {{emoji}}"

View File

@ -9,17 +9,17 @@
"inLists": "Listas contendo usuário ...", "inLists": "Listas contendo usuário ...",
"showBoosts": { "showBoosts": {
"action_false": "Mostrar boosts do usuário", "action_false": "Mostrar boosts do usuário",
"action_true": "" "action_true": "Ocultar boosts dos usuários"
}, },
"mute": { "mute": {
"action_false": "Silenciar usuário", "action_false": "Silenciar usuário",
"action_true": "Desativar o silêncio do usuário" "action_true": "Desativar o silêncio do usuário"
}, },
"followAs": { "followAs": {
"trigger": "", "trigger": "Seguir como ...",
"succeed_default": "Agora seguindo @{{target}} com @{{source}}", "succeed_default": "Agora seguindo @{{target}} com @{{source}}",
"succeed_locked": "", "succeed_locked": "Enviado o pedido para seguir @{{target}} com {{source}}, aguardando aprovação",
"failed": "" "failed": "Seguir como"
}, },
"blockReport": "Bloquear e denunciar", "blockReport": "Bloquear e denunciar",
"block": { "block": {
@ -38,7 +38,7 @@
}, },
"at": { "at": {
"direct": "Mensagem Direta", "direct": "Mensagem Direta",
"public": "" "public": "Mensagem pública"
}, },
"copy": { "copy": {
"action": "Copiar toot", "action": "Copiar toot",

View File

@ -3,7 +3,7 @@
"textInput": { "textInput": {
"placeholder": "Domínio da instância" "placeholder": "Domínio da instância"
}, },
"whitelisted": "", "whitelisted": "Esta pode ser uma instância na lista de permissões da qual o tooot não consegue recuperar dados antes de se conectar.",
"button": "Entrar", "button": "Entrar",
"information": { "information": {
"name": "Nome", "name": "Nome",

View File

@ -2,7 +2,7 @@
"HTML": { "HTML": {
"accessibilityHint": "Toque para expandir ou recolher conteúdo", "accessibilityHint": "Toque para expandir ou recolher conteúdo",
"expanded": "{{hint}}{{moreLines}}", "expanded": "{{hint}}{{moreLines}}",
"moreLines": "", "moreLines": " ({{count}} mais linhas)",
"defaultHint": "Toot longo" "defaultHint": "Toot longo"
} }
} }

View File

@ -20,7 +20,7 @@
"fetching": "Buscando toots mais recentes...", "fetching": "Buscando toots mais recentes...",
"fetched": { "fetched": {
"none": "Nenhum novo toot", "none": "Nenhum novo toot",
"found": "" "found": "toots {{count}} obtidos"
} }
}, },
"shared": { "shared": {
@ -33,12 +33,12 @@
"poll": "Uma enquete em que você votou terminou", "poll": "Uma enquete em que você votou terminou",
"reblog": { "reblog": {
"default": "{{name}} boostou", "default": "{{name}} boostou",
"myself": "", "myself": "Eu impulsionei",
"notification": "{{name}} deu boost no teu toot" "notification": "{{name}} deu boost no teu toot"
}, },
"update": "Toot foi editado", "update": "Toot foi editado",
"admin.sign_up": "", "admin.sign_up": "{{name}} entrou na instância",
"admin.report": "" "admin.report": "{{name}} relatou:"
}, },
"actions": { "actions": {
"reply": { "reply": {

View File

@ -11,13 +11,13 @@
"segments": { "segments": {
"federated": "Global", "federated": "Global",
"local": "Local", "local": "Local",
"explore": "" "explore": "Explorar"
}, },
"exploring": { "exploring": {
"heading": "", "heading": "Explorando",
"trending": "", "trending": "",
"followRemote": "", "followRemote": "",
"noTitle": "", "noTitle": "Sem título",
"errors": { "errors": {
"existed": "Você já está seguindo esta instância.", "existed": "Você já está seguindo esta instância.",
"notAvailable": "A linha do tempo desta instância não é acessível ao público. Por favor, tente outra instância." "notAvailable": "A linha do tempo desta instância não é acessível ao público. Por favor, tente outra instância."
@ -172,15 +172,15 @@
}, },
"filters": { "filters": {
"title": "Filtros de conteúdo", "title": "Filtros de conteúdo",
"content": "" "content": "{{count}} ativo"
}, },
"web_only": { "web_only": {
"title": "", "title": "Atualizar configurações",
"description": "As configurações abaixo só podem ser atualizadas usando a interface web" "description": "As configurações abaixo só podem ser atualizadas usando a interface web"
} }
}, },
"preferencesFilters": { "preferencesFilters": {
"expired": "", "expired": "Expirado",
"keywords_one": "{{count}} palavra-chave", "keywords_one": "{{count}} palavra-chave",
"keywords_other": "{{count}} palavras-chave", "keywords_other": "{{count}} palavras-chave",
"statuses_one": "{{count}} toot", "statuses_one": "{{count}} toot",
@ -271,8 +271,8 @@
"settings": "Ativar em configurações" "settings": "Ativar em configurações"
}, },
"missingServerKey": { "missingServerKey": {
"message": "", "message": "Servidor configurado incorretamente para push",
"description": "" "description": "Entre em contato com o administrador do servidor para configurar o suporte push"
}, },
"global": { "global": {
"heading": "Habilitar para {{acct}}", "heading": "Habilitar para {{acct}}",
@ -390,7 +390,7 @@
"accessibilityHint": "Você pode silenciar, bloquear, relatar ou compartilhar este usuário" "accessibilityHint": "Você pode silenciar, bloquear, relatar ou compartilhar este usuário"
}, },
"followed_by": " está seguindo você", "followed_by": " está seguindo você",
"privateNote": "", "privateNote": "Adicionar nota privada",
"moved": "Usuário movido", "moved": "Usuário movido",
"created_at": "Registrado em: {{date}}", "created_at": "Registrado em: {{date}}",
"summary": { "summary": {
@ -404,7 +404,7 @@
}, },
"accountInLists": { "accountInLists": {
"name": "Listas de @{{username}}", "name": "Listas de @{{username}}",
"inLists": "", "inLists": "Nas listas",
"notInLists": "Outras listas" "notInLists": "Outras listas"
}, },
"attachments": { "attachments": {
@ -417,6 +417,20 @@
"history": { "history": {
"name": "Histórico de Edição" "name": "Histórico de Edição"
}, },
"mute": {
"name": "Silenciar {{acct}}",
"mute": "Silenciar",
"description": "Oculte postagens e menções a este usuário, mas isso ainda permitirá que ele veja suas postagens e siga você.",
"notification": "Ocultar também notificações deste usuário",
"duration": {
"heading": "Por duração",
"0": "Indefinidamente",
"1800": "30 minutos",
"3600": "1 hora",
"86400": "1 dia",
"604800": "1 semana"
}
},
"report": { "report": {
"name": "Denuncia {{acct}}", "name": "Denuncia {{acct}}",
"report": "Denunciar", "report": "Denunciar",
@ -467,7 +481,7 @@
"toot": { "toot": {
"name": "Discussões", "name": "Discussões",
"remoteFetch": { "remoteFetch": {
"title": "", "title": "Contém conteúdo remoto",
"message": "O conteúdo global nem sempre está disponível na instância local. Estes conteúdos são obtidos de instâncias remotas e marcados. Você pode interagir com esses conteúdos normalmente." "message": "O conteúdo global nem sempre está disponível na instância local. Estes conteúdos são obtidos de instâncias remotas e marcados. Você pode interagir com esses conteúdos normalmente."
} }
}, },

View File

@ -9,7 +9,7 @@
"delete": "Удалить", "delete": "Удалить",
"done": "Готово", "done": "Готово",
"confirm": "Подтвердить", "confirm": "Подтвердить",
"add": "" "add": "Добавить"
}, },
"customEmoji": { "customEmoji": {
"accessibilityLabel": "Пользовательские эмодзи {{emoji}}" "accessibilityLabel": "Пользовательские эмодзи {{emoji}}"

View File

@ -7,7 +7,7 @@
"button": "Войти", "button": "Войти",
"information": { "information": {
"name": "Название", "name": "Название",
"description": "" "description": "Описание"
}, },
"disclaimer": { "disclaimer": {
"base": "Вход в систему использует системный браузер, информация о вашем аккаунте не будет видна приложению." "base": "Вход в систему использует системный браузер, информация о вашем аккаунте не будет видна приложению."

View File

@ -1,8 +1,8 @@
{ {
"HTML": { "HTML": {
"accessibilityHint": "", "accessibilityHint": "Нажмите, чтобы развернуть или свернуть содержимое",
"expanded": "", "expanded": "{{hint}}{{moreLines}}",
"moreLines": "", "moreLines": " ({{count}} больше строк)",
"defaultHint": "" "defaultHint": "Длинное сообщение"
} }
} }

View File

@ -1,16 +1,16 @@
{ {
"follow": { "follow": {
"function": "" "function": "Подписаться на пользователя"
}, },
"block": { "block": {
"function": "" "function": "Заблокировать пользователя"
}, },
"button": { "button": {
"error": "", "error": "Ошибка загрузки",
"blocked_by": "", "blocked_by": "Заблокирован пользователем",
"blocking": "", "blocking": "Разблокировать",
"following": "", "following": "Отписаться",
"requested": "", "requested": "Отменить запрос",
"default": "" "default": "Подписаться"
} }
} }

View File

@ -1,81 +1,81 @@
{ {
"empty": { "empty": {
"error": { "error": {
"message": "", "message": "Ошибка загрузки",
"button": "" "button": "Повторить"
}, },
"success": { "success": {
"message": "" "message": "Лента пуста"
} }
}, },
"end": { "end": {
"message": "" "message": "Конец, как насчет чашки <0 />"
}, },
"lookback": { "lookback": {
"message": "" "message": "Последний просмотр в"
}, },
"refresh": { "refresh": {
"fetchPreviousPage": "", "fetchPreviousPage": "Новинки отсюда",
"refetch": "", "refetch": "В конец",
"fetching": "", "fetching": "Получение новых сообщений ...",
"fetched": { "fetched": {
"none": "", "none": "Нет новых сообщений",
"found": "" "found": "Получено {{count}} сообщений"
} }
}, },
"shared": { "shared": {
"actioned": { "actioned": {
"pinned": "Закрепить", "pinned": "Закрепить",
"favourite": "", "favourite": "{{name}} добавил(а) ваш пост в избранное",
"status": "{{name}} только что запостил", "status": "{{name}} только что запостил",
"follow": "{{name}} подписался (-лась) на вас", "follow": "{{name}} подписался (-лась) на вас",
"follow_request": "{{name}} хочет подписаться на вас", "follow_request": "{{name}} хочет подписаться на вас",
"poll": "", "poll": "Опрос, в котором вы участвовали, завершен",
"reblog": { "reblog": {
"default": "", "default": "{{name}} продвинул(а)",
"myself": "", "myself": "Я продвинул(а)",
"notification": "" "notification": "{{name}} продвинул(а) ваш пост"
}, },
"update": "", "update": "Репост был отредактирован",
"admin.sign_up": "", "admin.sign_up": "{{name}} присоединился к серверу",
"admin.report": "" "admin.report": "{{name}} сообщил(а):"
}, },
"actions": { "actions": {
"reply": { "reply": {
"accessibilityLabel": "" "accessibilityLabel": "Ответить на это сообщение"
}, },
"reblogged": { "reblogged": {
"accessibilityLabel": "", "accessibilityLabel": "Продвинуть это сообщение",
"function": "", "function": "Продвинуть сообщение",
"options": { "options": {
"title": "", "title": "Выберите видимость продвижения",
"public": "", "public": "Публичное продвижение",
"unlisted": "" "unlisted": "Убрать из списка"
} }
}, },
"favourited": { "favourited": {
"accessibilityLabel": "", "accessibilityLabel": "Добавить этот пост в избранное",
"function": "" "function": "Избранное"
}, },
"bookmarked": { "bookmarked": {
"accessibilityLabel": "", "accessibilityLabel": "Добавить этот пост в закладки",
"function": "" "function": "Закладки"
}, },
"openReport": "" "openReport": "Открыть отчет"
}, },
"actionsUsers": { "actionsUsers": {
"reblogged_by": { "reblogged_by": {
"accessibilityLabel": "", "accessibilityLabel": "{{count}} пользователей продвинули этот пост",
"accessibilityHint": "", "accessibilityHint": "Нажмите, чтобы узнать пользователей",
"text": "" "text": "$t(screenTabs:shared.users.statuses.reblogged_by)"
}, },
"favourited_by": { "favourited_by": {
"accessibilityLabel": "", "accessibilityLabel": "{{count}} пользователей добавили этот пост в избранное",
"accessibilityHint": "", "accessibilityHint": "Нажмите, чтобы узнать пользователей",
"text": "" "text": "$t(screenTabs:shared.users.statuses.favourited_by)"
}, },
"history": { "history": {
"accessibilityLabel": "", "accessibilityLabel": "Этот пост был отредактирован {{count}} раз",
"accessibilityHint": "", "accessibilityHint": "",
"text_one": "", "text_one": "",
"text_other": "" "text_other": ""

View File

@ -417,6 +417,20 @@
"history": { "history": {
"name": "" "name": ""
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "",
"1800": "",
"3600": "",
"86400": "",
"604800": ""
}
},
"report": { "report": {
"name": "", "name": "",
"report": "", "report": "",

View File

@ -9,7 +9,7 @@
"delete": "Radera", "delete": "Radera",
"done": "Klar", "done": "Klar",
"confirm": "Bekräfta", "confirm": "Bekräfta",
"add": "" "add": "Lägg till"
}, },
"customEmoji": { "customEmoji": {
"accessibilityLabel": "Anpassad emoji {{emoji}}" "accessibilityLabel": "Anpassad emoji {{emoji}}"

View File

@ -16,7 +16,7 @@
"action_true": "Sluta tysta användare" "action_true": "Sluta tysta användare"
}, },
"followAs": { "followAs": {
"trigger": "", "trigger": "Följ som ...",
"succeed_default": "Följer nu @{{target}} med @{{source}}", "succeed_default": "Följer nu @{{target}} med @{{source}}",
"succeed_locked": "Följförfrågan skickades till @{{target}} med {{source}}, väntar på godkännande", "succeed_locked": "Följförfrågan skickades till @{{target}} med {{source}}, väntar på godkännande",
"failed": "Följ som" "failed": "Följ som"
@ -56,7 +56,7 @@
}, },
"hashtag": { "hashtag": {
"follow": { "follow": {
"action_false": "", "action_false": "Följ",
"action_true": "" "action_true": ""
}, },
"filter": { "filter": {
@ -100,7 +100,7 @@
}, },
"filter": { "filter": {
"action_false": "", "action_false": "",
"action_true": "" "action_true": "Hantera filter ..."
} }
} }
} }

View File

@ -83,13 +83,13 @@
"name": "" "name": ""
}, },
"preferencesFilters": { "preferencesFilters": {
"name": "" "name": "Alla innehållsfilter"
}, },
"preferencesFilterAdd": { "preferencesFilterAdd": {
"name": "" "name": "Skapa ett filter"
}, },
"preferencesFilterEdit": { "preferencesFilterEdit": {
"name": "" "name": "Redigera filter"
}, },
"profile": { "profile": {
"name": "Redigera profil" "name": "Redigera profil"
@ -150,7 +150,7 @@
"options": { "options": {
"public": "", "public": "",
"unlisted": "", "unlisted": "",
"private": "" "private": "Endast följare"
} }
}, },
"sensitive": { "sensitive": {
@ -181,8 +181,8 @@
}, },
"preferencesFilters": { "preferencesFilters": {
"expired": "", "expired": "",
"keywords_one": "", "keywords_one": "{{count}} nyckelord",
"keywords_other": "", "keywords_other": "{{count}} nyckelord",
"statuses_one": "", "statuses_one": "",
"statuses_other": "", "statuses_other": "",
"context": "", "context": "",
@ -191,20 +191,20 @@
"notifications": "", "notifications": "",
"public": "", "public": "",
"thread": "", "thread": "",
"account": "" "account": "profil"
} }
}, },
"preferencesFilter": { "preferencesFilter": {
"name": "", "name": "Namn",
"expiration": "", "expiration": "",
"expirationOptions": { "expirationOptions": {
"0": "", "0": "Aldrig",
"1800": "", "1800": "Efter 30 minuter",
"3600": "", "3600": "Efter 1 timme",
"43200": "", "43200": "Efter 12 timmar",
"86400": "", "86400": "Efter 1 dag",
"604800": "", "604800": "Efter 1 vecka",
"18144000": "" "18144000": "Efter 1 månad"
}, },
"context": "", "context": "",
"contexts": { "contexts": {
@ -417,6 +417,20 @@
"history": { "history": {
"name": "Redigeringshistorik" "name": "Redigeringshistorik"
}, },
"mute": {
"name": "",
"mute": "",
"description": "",
"notification": "",
"duration": {
"heading": "",
"0": "",
"1800": "30 minuter",
"3600": "1 timme",
"86400": "1 dag",
"604800": "1 vecka"
}
},
"report": { "report": {
"name": "Rapportera {{acct}}", "name": "Rapportera {{acct}}",
"report": "Rapport", "report": "Rapport",

View File

@ -129,7 +129,7 @@
"muted": { "muted": {
"accessibilityLabel": "Дмух приглушений" "accessibilityLabel": "Дмух приглушений"
}, },
"replies": "", "replies": "Відповіді <0 />",
"visibility": { "visibility": {
"direct": { "direct": {
"accessibilityLabel": "Дмухнути особистим повідомленням" "accessibilityLabel": "Дмухнути особистим повідомленням"

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