Compare commits

...

372 Commits
v4.7.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
xmflsct 3238f44867 Fix crash 2023-03-14 23:48:35 +01:00
xmflsct c698ba84e6
New Crowdin updates (#721)
* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Basque)

* New translations tabs.json (Basque)

* New translations contextMenu.json (Basque)

* New translations accountSelection.json (Basque)
2023-03-14 21:54:22 +01:00
xmflsct 288a5f12da Added Polish language 2023-03-14 21:49:14 +01:00
xmflsct 791edcc342 Added Basque language 2023-03-14 21:44:13 +01:00
xmflsct bfe37db9b6 Refine remote logic
When loading remote ancestors, the position might not be kept
2023-03-14 21:28:41 +01:00
xmflsct b5ddebe123 Fix some zoomed image not shown correctly 2023-03-14 21:14:09 +01:00
xmflsct 4977e91b66 Fix #722 2023-03-14 20:56:16 +01:00
xmflsct 5b640879f0 Bump packages 2023-03-14 20:37:41 +01:00
xmflsct a0b3b38d8d Add new types #722 2023-03-14 10:50:22 +01:00
xmflsct f78693eee8 Locale lower case match 2023-03-14 01:39:54 +01:00
xmflsct 4e620f8987 Test #722 2023-03-14 00:40:28 +01:00
xmflsct f8a3b56b11 Remove direct dependency of url-parse 2023-03-13 23:16:41 +01:00
xmflsct 63900c4338 Fix #719 2023-03-12 19:45:09 +01:00
xmflsct 1df73b070a Fix #716 2023-03-12 18:49:06 +01:00
xmflsct 173d4248d8 Fix #717 2023-03-12 18:09:33 +01:00
xmflsct 0db7f0c40a Update based on Expo's template 2023-03-10 21:19:45 +01:00
xmflsct 921d6e1f4b
New translations tabs.json (Belarusian) (#715) 2023-03-10 14:04:24 +01:00
xmflsct 43d2601660 Fix #706
Very strange bug again only on Android of drawing svgs
2023-03-10 14:04:01 +01:00
xmflsct 97fb5b8e6d Bump packages 2023-03-10 14:03:10 +01:00
xmflsct af991fdc56 For #711 2023-03-10 13:45:01 +01:00
xmflsct 6e8cefd7c2 Attempt to fix #711
Why get device token would fail without error message?
2023-03-10 00:04:07 +01:00
xmflsct 5c461c0cd1
New Crowdin updates (#710)
* New translations screens.json (Basque)

* New translations tabs.json (Basque)

* New translations tabs.json (Basque)

* New translations tabs.json (Basque)

* New translations tabs.json (Basque)

* New translations contextMenu.json (Basque)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)
2023-03-08 23:40:47 +01:00
xmflsct 6dee67a4de Added Belarusian 2023-03-08 23:40:28 +01:00
xmflsct abf3d41780 Bump 2023-03-08 21:40:40 +01:00
xmflsct f58b2af631 Bump 2023-03-04 17:37:05 +01:00
xmflsct 0450019cac Fix push token not updated 2023-02-28 20:43:37 +01:00
xmflsct 4ce3ce58ab
New Crowdin updates (#709)
* New translations compose.json (Basque)

* New translations tabs.json (Basque)

* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Portuguese, Brazilian)

* New translations compose.json (Basque)

* New translations tabs.json (Basque)

* New translations compose.json (Basque)

* New translations screens.json (Basque)

* New translations tabs.json (Basque)

* New translations tabs.json (Dutch)

* New translations tabs.json (Ukrainian)

* New translations instance.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations instance.json (Belarusian)

* New translations timeline.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Norwegian)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Spanish)

* New translations tabs.json (Catalan)

* New translations tabs.json (Belarusian)

* New translations tabs.json (Belarusian)
2023-02-27 18:57:10 +01:00
xmflsct c44482aa75 Remove disable auto refetch
Now remote instance page has auto hide heading
2023-02-27 18:56:36 +01:00
xmflsct 120641b95e Improve account page 2023-02-26 21:51:31 +01:00
xmflsct 71e0c88cc2 Fix conversation view append timeline jump 2023-02-26 18:09:51 +01:00
xmflsct 702ecef243 Fetch remote user's toots 2023-02-25 23:42:04 +01:00
xmflsct f505f78193 Update PrivateNotes.tsx 2023-02-25 22:24:23 +01:00
xmflsct 292fb42a22 Fix change remote and refresh 2023-02-25 22:20:44 +01:00
xmflsct 216a736860 Fix account page account issue 2023-02-25 21:57:11 +01:00
xmflsct 8b721e1d2e
New Crowdin updates (#705)
* New translations tabs.json (Chinese Traditional)

* New translations common.json (Belarusian)

* New translations common.json (German)

* New translations common.json (Dutch)

* New translations parse.json (Belarusian)

* New translations relationship.json (Belarusian)

* New translations timeline.json (Belarusian)

* New translations imageViewer.json (Belarusian)

* New translations compose.json (Belarusian)

* New translations screens.json (Belarusian)

* New translations tabs.json (French)

* New translations tabs.json (Spanish)

* New translations tabs.json (Belarusian)

* 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 mediaSelector.json (Belarusian)

* New translations contextMenu.json (Belarusian)

* New translations tabs.json (Chinese Simplified)
2023-02-25 17:05:43 +01:00
xmflsct de7e39a332 Update Crowdin configuration file 2023-02-25 16:55:42 +01:00
xmflsct 4269c1d9d1 Refine adding remote instance 2023-02-25 16:52:38 +01:00
xmflsct 35eb7ba765 Stop auto refetch when pressing on nav icon
Fix #708
2023-02-25 16:00:08 +01:00
xmflsct 45c54db617 Fallback to expo beta for blurhash to function 2023-02-25 15:28:01 +01:00
xmflsct 1bff79ed4a Bump 2023-02-25 00:34:37 +01:00
xmflsct ca2e1e07ec Bump Sentry 2023-02-24 14:05:29 +01:00
xmflsct 04a56edcf4 Fix bugs 2023-02-24 13:54:27 +01:00
xmflsct b1a796d3f1 Bump packages 2023-02-24 13:06:20 +01:00
xmflsct 73e4bdb290 Prevent image loading flashing in conversation 2023-02-17 22:19:04 +01:00
xmflsct d2eb7156a4 Try faster append toots 2023-02-17 18:58:43 +01:00
xmflsct 9b0f07fbf1 Some clean up 2023-02-17 14:22:54 +01:00
xmflsct 542dfe4723 Try using default windowSize 2023-02-17 14:04:30 +01:00
xmflsct 3b9369b509 Fix Norwegian fallbacks 2023-02-17 13:53:16 +01:00
xmflsct 8b8a540105 Added Norwegian
Would it be confused between `nb` and `nn`?
2023-02-16 23:44:28 +01:00
xmflsct 001267b9c7 Remove sentry instrucmentation 2023-02-16 23:36:01 +01:00
xmflsct 718870e3e9 Load less per page 2023-02-16 20:42:16 +01:00
xmflsct 86e7edb963 Bump 2023-02-15 19:31:26 +01:00
xmflsct ad04eff7ce Try out using margin instead of gap 2023-02-14 23:18:23 +01:00
xmflsct 3b4b6d2f67 Fix iOS building 2023-02-14 23:15:01 +01:00
xmflsct c0798a2e0c Fix Android building crash
https://github.com/software-mansion/react-native-reanimated/issues/3615#issuecomment-1260485861
2023-02-14 23:12:26 +01:00
xmflsct 29d5a1508d Bump packages 2023-02-14 23:04:28 +01:00
xmflsct ea54f91f29 Update Video.tsx 2023-02-13 22:02:48 +01:00
xmflsct 6a8663f9ed Update Toot.tsx 2023-02-13 21:43:02 +01:00
xmflsct 71e3bce422 Bump reanimated 2023-02-13 21:38:02 +01:00
xmflsct 781752ee91
New Crowdin updates (#703)
* New translations tabs.json (Korean)

* New translations common.json (Belarusian)

* New translations instance.json (Belarusian)

* New translations parse.json (Belarusian)

* New translations relationship.json (Belarusian)

* New translations timeline.json (Belarusian)

* New translations imageViewer.json (Belarusian)

* New translations announcements.json (Belarusian)

* New translations compose.json (Belarusian)

* New translations screens.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations mediaSelector.json (Belarusian)

* New translations emojis.json (Belarusian)

* New translations contextMenu.json (Belarusian)

* New translations accountSelection.json (Belarusian)

* New translations instance.json (Belarusian)

* New translations screens.json (Belarusian)

* New translations mediaSelector.json (Belarusian)

* New translations emojis.json (Belarusian)

* New translations parse.json (Belarusian)

* New translations relationship.json (Belarusian)

* New translations timeline.json (Belarusian)

* New translations announcements.json (Belarusian)

* New translations compose.json (Belarusian)

* New translations mediaSelector.json (Belarusian)

* New translations accountSelection.json (Belarusian)

* New translations timeline.json (Catalan)

* New translations tabs.json (Catalan)

* New translations common.json (French)

* New translations common.json (Spanish)

* New translations common.json (Catalan)

* New translations common.json (Czech)

* New translations common.json (German)

* New translations common.json (Greek)

* New translations common.json (Basque)

* New translations common.json (Italian)

* New translations common.json (Japanese)

* New translations common.json (Korean)

* New translations common.json (Dutch)

* New translations common.json (Polish)

* New translations common.json (Russian)

* New translations common.json (Swedish)

* New translations common.json (Ukrainian)

* New translations common.json (Chinese Simplified)

* New translations common.json (Chinese Traditional)

* New translations common.json (Vietnamese)

* New translations common.json (Portuguese, Brazilian)

* New translations instance.json (French)

* New translations instance.json (Spanish)

* New translations instance.json (Catalan)

* New translations instance.json (Czech)

* New translations instance.json (German)

* New translations instance.json (Greek)

* New translations instance.json (Basque)

* New translations instance.json (Italian)

* New translations instance.json (Japanese)

* New translations instance.json (Korean)

* New translations instance.json (Dutch)

* New translations instance.json (Polish)

* New translations instance.json (Russian)

* New translations instance.json (Swedish)

* New translations instance.json (Ukrainian)

* New translations instance.json (Chinese Simplified)

* New translations instance.json (Chinese Traditional)

* New translations instance.json (Vietnamese)

* New translations instance.json (Portuguese, Brazilian)

* 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 (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 common.json (Norwegian)

* New translations instance.json (Norwegian)

* New translations tabs.json (Norwegian)

* New translations common.json (Belarusian)

* New translations instance.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations common.json (Chinese Simplified)

* New translations instance.json (French)

* New translations instance.json (Spanish)

* New translations instance.json (Catalan)

* New translations instance.json (German)

* New translations instance.json (Greek)

* New translations instance.json (Japanese)

* New translations instance.json (Korean)

* New translations instance.json (Dutch)

* New translations instance.json (Polish)

* New translations instance.json (Swedish)

* New translations instance.json (Ukrainian)

* New translations instance.json (Chinese Simplified)

* New translations instance.json (Chinese Traditional)

* New translations instance.json (Vietnamese)

* New translations instance.json (Portuguese, Brazilian)

* New translations tabs.json (Chinese Simplified)

* New translations instance.json (Norwegian)

* New translations common.json (Basque)

* New translations common.json (Chinese Traditional)

* New translations instance.json (Basque)

* 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 (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 common.json (Norwegian)

* New translations tabs.json (Norwegian)

* New translations common.json (Belarusian)

* New translations instance.json (Belarusian)

* New translations tabs.json (Belarusian)

* New translations parse.json (Basque)

* New translations timeline.json (Basque)

* New translations imageViewer.json (Basque)

* New translations announcements.json (Basque)

* New translations compose.json (Basque)

* New translations common.json (Spanish)

* New translations common.json (Catalan)

* New translations common.json (Ukrainian)

* New translations tabs.json (Spanish)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Norwegian)

* New translations tabs.json (Chinese Simplified)
2023-02-12 23:08:29 +01:00
xmflsct a78fe5ffe8 Added attachment border radius 2023-02-12 23:08:15 +01:00
xmflsct e37a95408c Fix #608 2023-02-12 19:47:28 +01:00
xmflsct d3cf0edbc9 Align discard confirmation 2023-02-12 18:47:03 +01:00
xmflsct 79a92b5df7 Fix #667 2023-02-12 18:38:06 +01:00
xmflsct 4a340fca8e Fix remote toot not interactable 2023-02-12 17:08:44 +01:00
xmflsct 398f34d95d Narrower attachments
For #704
2023-02-12 15:50:55 +01:00
xmflsct 3eec9d1af0 Try to fix App Store warning 2023-02-12 15:00:59 +01:00
xmflsct 127978da79 Fix #612 2023-02-12 14:50:31 +01:00
xmflsct 441090ab28 Improve audio player 2023-02-11 23:46:12 +01:00
xmflsct 242c75079a Use the new gap option 2023-02-11 23:37:17 +01:00
xmflsct b679c0760f Fix ts warnings 2023-02-11 22:04:32 +01:00
xmflsct fcc53672fa Build passed 2023-02-11 19:15:34 +01:00
xmflsct 620dcfccdb Fix #702 2023-02-11 18:12:50 +01:00
xmflsct 2de5a251ce Bump packages 2023-02-11 18:04:03 +01:00
xmflsct 2097dceda7
New Crowdin updates (#694)
* New translations timeline.json (Spanish)

* New translations timeline.json (Catalan)

* New translations timeline.json (Basque)

* New translations timeline.json (Ukrainian)

* New translations common.json (Norwegian)

* New translations instance.json (Norwegian)

* New translations parse.json (Norwegian)

* New translations relationship.json (Norwegian)

* New translations timeline.json (Norwegian)

* New translations imageViewer.json (Norwegian)

* New translations announcements.json (Norwegian)

* New translations compose.json (Norwegian)

* New translations screens.json (Norwegian)

* New translations tabs.json (Norwegian)

* New translations mediaSelector.json (Norwegian)

* New translations emojis.json (Norwegian)

* New translations contextMenu.json (Norwegian)

* New translations accountSelection.json (Norwegian)

* New translations common.json (Norwegian)

* New translations common.json (Norwegian)

* New translations instance.json (Norwegian)

* New translations parse.json (Norwegian)

* New translations relationship.json (Norwegian)

* New translations timeline.json (Norwegian)

* New translations imageViewer.json (Norwegian)

* New translations announcements.json (Norwegian)

* New translations compose.json (Norwegian)

* New translations screens.json (Norwegian)

* New translations tabs.json (Norwegian)

* New translations parse.json (Norwegian)

* New translations timeline.json (Norwegian)

* New translations compose.json (Norwegian)

* New translations screens.json (Norwegian)

* New translations tabs.json (Norwegian)

* New translations mediaSelector.json (Norwegian)

* New translations emojis.json (Norwegian)

* New translations contextMenu.json (Norwegian)

* New translations accountSelection.json (Norwegian)

* New translations timeline.json (Korean)

* New translations compose.json (Korean)

* New translations tabs.json (Korean)

* New translations contextMenu.json (Korean)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* New translations timeline.json (Japanese)

* New translations tabs.json (Japanese)

* New translations timeline.json (German)
2023-02-09 14:36:46 +01:00
xmflsct eecd871d65 Fix avatar not updated 2023-02-09 14:19:50 +01:00
xmflsct 4864f6cd5c Fix #701 2023-02-09 14:11:54 +01:00
xmflsct 0185335138 Fix image viewer placeholder 2023-02-08 21:41:16 +01:00
xmflsct 48481a4cd5 Improve auto fetch 2023-02-08 19:22:20 +01:00
xmflsct 724cd76647 Bump deps 2023-02-08 01:33:12 +01:00
xmflsct 11ac2bd51d Update yarn.lock 2023-02-08 01:30:35 +01:00
xmflsct d1ed8a0d2a Test #700 2023-02-08 01:10:59 +01:00
dependabot[bot] 9259ee2995
Bump http-cache-semantics from 4.1.0 to 4.1.1 (#696)
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-07 23:42:51 +01:00
xmflsct c1ebde8fe9 Fix #699 2023-02-07 23:38:34 +01:00
xmflsct 8775a0cb25 Fix #697 2023-02-07 22:19:39 +01:00
xmflsct 0b3d206190 Fix #698 2023-02-07 21:41:06 +01:00
xmflsct fd114ed0f0 Check for Wildebeest's account ID format 2023-02-07 15:06:04 +01:00
xmflsct f98b8946dc Refine marker 2023-02-07 13:56:50 +01:00
xmflsct be2c223142 Mark id on load
With the introduction of throttle, it is crucial to log on load otherwise there won't be much match after that
2023-02-06 19:07:22 +01:00
xmflsct 5d1459eba6 Fix some toots not interactable 2023-02-06 18:58:55 +01:00
xmflsct 1dd64c4e19 Fix link matching crashes 2023-02-06 14:00:40 +01:00
xmflsct 9f6e7738bf Fix when userTheme is undefined 2023-02-03 16:06:18 +01:00
xmflsct adddae9d72 Refine push 2023-02-03 15:54:04 +01:00
xmflsct db41e85d07
New Crowdin updates (#690)
* New translations timeline.json (Basque)

* New translations timeline.json (Portuguese, Brazilian)

* New translations tabs.json (Portuguese, Brazilian)

* New translations timeline.json (Japanese)

* New translations tabs.json (Japanese)

* New translations contextMenu.json (Japanese)

* New translations timeline.json (German)

* New translations contextMenu.json (German)

* New translations instance.json (German)

* New translations timeline.json (German)

* New translations tabs.json (German)

* New translations contextMenu.json (German)

* New translations timeline.json (French)

* New translations timeline.json (Spanish)

* New translations timeline.json (Catalan)

* New translations timeline.json (Czech)

* New translations timeline.json (German)

* New translations timeline.json (Greek)

* New translations timeline.json (Basque)

* New translations timeline.json (Italian)

* New translations timeline.json (Japanese)

* New translations timeline.json (Korean)

* New translations timeline.json (Dutch)

* New translations timeline.json (Polish)

* New translations timeline.json (Russian)

* New translations timeline.json (Swedish)

* New translations timeline.json (Ukrainian)

* New translations timeline.json (Chinese Simplified)

* New translations timeline.json (Chinese Traditional)

* New translations timeline.json (Vietnamese)

* New translations timeline.json (Portuguese, Brazilian)

* New translations timeline.json (Dutch)

* New translations timeline.json (Swedish)

* New translations timeline.json (Chinese Simplified)

* New translations timeline.json (Chinese Traditional)
2023-02-03 14:47:48 +01:00
xmflsct e225c5b6bf Clarify my own boosts 2023-02-03 13:57:11 +01:00
xmflsct 7c7c96bc42 Update HTML.tsx 2023-02-03 13:48:29 +01:00
xmflsct 242ecf76c0 Improve marker loading
Actually the id can be invalid (not found), and the timeline can be loaded to the right position, therefore no need to check the id anymore.
2023-02-03 13:11:15 +01:00
xmflsct 2a774a5516 Should fix #692 2023-02-03 12:07:17 +01:00
xmflsct 5ec49739fc Let lib handles cache 2023-02-03 00:59:39 +01:00
xmflsct 3545c13ae9 Update Podfile.lock 2023-02-02 15:27:14 +01:00
xmflsct 74badd94cb Improve refresh loading 2023-02-02 14:15:37 +01:00
xmflsct 2d9f7a90cc Bump packages 2023-02-02 14:15:14 +01:00
xmflsct 90c8e4cba8 Fix #691
One liner fix, but took some time to find out...
2023-02-02 13:54:28 +01:00
xmflsct 2c96991ca0 Fix push page not refetching 2023-02-01 15:04:22 +01:00
xmflsct 0dacd5ec89 Fix error message returning key in poll 2023-02-01 14:52:16 +01:00
xmflsct 88d4de98c2 Fix poll in "remote" toots not working 2023-02-01 14:40:22 +01:00
xmflsct 78b6834c3f Do not fade in when blurhash or preview has been loaded 2023-02-01 13:53:18 +01:00
xmflsct e60535cd1c Catch potentially json parsing error 2023-02-01 00:07:38 +01:00
xmflsct 5d3f773a2a Faster image loading transition 2023-02-01 00:06:33 +01:00
xmflsct 968a3266c2 Test clearing disk cache 2023-01-31 15:19:18 +01:00
xmflsct c21e99909d Add fade in transition of react-native-fast-image
Based on https://github.com/DylanVann/react-native-fast-image/pull/958
2023-01-31 15:15:15 +01:00
xmflsct 624c1f172c Use the same subdomain for connect media
Preventing count as cache miss
2023-01-31 14:26:43 +01:00
xmflsct 602e010cfc
Update name.txt 2023-01-30 15:36:59 +01:00
xmflsct 49c51b4af2
Update connect.ts 2023-01-30 14:53:08 +01:00
xmflsct 574dbd3258
New Crowdin updates (#686)
* New translations timeline.json (Portuguese, Brazilian)

* New translations tabs.json (Portuguese, Brazilian)

* New translations tabs.json (Portuguese, Brazilian)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations timeline.json (Dutch)

* New translations timeline.json (Chinese Traditional)

* New translations timeline.json (Spanish)

* New translations timeline.json (Catalan)

* New translations timeline.json (Ukrainian)

* New translations tabs.json (Spanish)

* New translations tabs.json (Catalan)
2023-01-30 13:53:37 +01:00
xmflsct dc893b0d5d Reset when verification failed 2023-01-30 13:53:21 +01:00
xmflsct 4aa96ba2bd Fix #683
Affects both platforms
2023-01-30 13:44:29 +01:00
xmflsct 646b539949 Improve notify animation 2023-01-30 13:40:43 +01:00
xmflsct 7559196e42 Merge branch 'main' of https://github.com/tooot-app/app 2023-01-30 13:40:28 +01:00
xmflsct 57efc4c868 Fix crashes 2023-01-30 12:55:35 +01:00
xmflsct f219371243
Update package.json 2023-01-30 01:20:24 +01:00
xmflsct 5551cd0e12
New Crowdin updates (#684)
* New translations common.json (Portuguese, Brazilian)

* New translations timeline.json (Portuguese, Brazilian)

* New translations tabs.json (Spanish)

* New translations tabs.json (Catalan)

* New translations tabs.json (Portuguese, Brazilian)

* New translations tabs.json (Portuguese, Brazilian)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations timeline.json (French)

* New translations timeline.json (Spanish)

* New translations timeline.json (Catalan)

* New translations timeline.json (Czech)

* New translations timeline.json (German)

* New translations timeline.json (Greek)

* New translations timeline.json (Basque)

* New translations timeline.json (Italian)

* New translations timeline.json (Japanese)

* New translations timeline.json (Korean)

* New translations timeline.json (Dutch)

* New translations timeline.json (Polish)

* New translations timeline.json (Russian)

* New translations timeline.json (Swedish)

* New translations timeline.json (Ukrainian)

* New translations timeline.json (Chinese Simplified)

* New translations timeline.json (Chinese Traditional)

* New translations timeline.json (Vietnamese)

* New translations timeline.json (Portuguese, Brazilian)

* New translations contextMenu.json (Spanish)

* New translations contextMenu.json (Catalan)

* New translations timeline.json (Chinese Simplified)
2023-01-30 00:48:08 +01:00
xmflsct 90b0178f5d Refetch only latest pages 2023-01-30 00:36:16 +01:00
xmflsct d1714fab26 Added fetched notice 2023-01-30 00:25:46 +01:00
xmflsct aee206fc95 Refine account switching 2023-01-29 22:18:33 +01:00
xmflsct 062e6825b5 Reuse account info when navigating 2023-01-29 21:53:13 +01:00
xmflsct 83cd5d4eb0 Suppress spoiler for easier reading
As spoiler is default expanded now in thread
2023-01-29 19:27:15 +01:00
xmflsct aba239188f Black list path format includes @ but not Mastodon 2023-01-29 19:04:21 +01:00
xmflsct 5c3e490112 Use in-memory global values
As connect needs to be read very often
2023-01-29 19:02:47 +01:00
xmflsct ebe57be674 Update descriptions 2023-01-29 17:39:25 +01:00
xmflsct 752d33d5b3 Dimming images for dark mode 2023-01-29 17:28:49 +01:00
xmflsct e447a91cfb Fix remote prop not appended in all places 2023-01-29 16:59:14 +01:00
xmflsct 8c87841fed Improve account switch hint 2023-01-29 16:20:31 +01:00
xmflsct 95a99ef7cd Try out connect 2023-01-29 15:32:40 +01:00
xmflsct 3451a021e9 Update package.json 2023-01-29 00:38:44 +01:00
xmflsct eff1f97b14
New translations tabs.json (Vietnamese) (#678) 2023-01-29 00:38:29 +01:00
xmflsct 40522595d0 Fix #682 #681 2023-01-29 00:37:56 +01:00
xmflsct af5273d216
New Crowdin updates (#677)
* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Polish)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (German)

* New translations parse.json (Portuguese, Brazilian)

* New translations timeline.json (Portuguese, Brazilian)

* New translations mediaSelector.json (Portuguese, Brazilian)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations tabs.json (German)

* New translations tabs.json (Portuguese, Brazilian)

* New translations common.json (Portuguese, Brazilian)

* New translations common.json (Basque)

* New translations common.json (Basque)

* New translations instance.json (Basque)

* New translations parse.json (Basque)

* New translations relationship.json (Basque)

* New translations relationship.json (Basque)

* New translations timeline.json (Basque)

* New translations timeline.json (Catalan)

* New translations tabs.json (Catalan)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* 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 (French)

* New translations tabs.json (Polish)

* New translations tabs.json (Spanish)

* New translations tabs.json (Swedish)

* New translations tabs.json (Czech)

* New translations tabs.json (Dutch)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Russian)

* New translations tabs.json (Greek)

* New translations tabs.json (Basque)

* New translations contextMenu.json (French)

* New translations contextMenu.json (Spanish)

* New translations contextMenu.json (Catalan)

* New translations contextMenu.json (Czech)

* New translations contextMenu.json (German)

* New translations contextMenu.json (Greek)

* New translations contextMenu.json (Basque)

* New translations contextMenu.json (Italian)

* New translations contextMenu.json (Japanese)

* New translations contextMenu.json (Korean)

* New translations contextMenu.json (Dutch)

* New translations contextMenu.json (Polish)

* New translations contextMenu.json (Russian)

* New translations contextMenu.json (Swedish)

* New translations contextMenu.json (Ukrainian)

* New translations contextMenu.json (Chinese Simplified)

* New translations contextMenu.json (Chinese Traditional)

* New translations contextMenu.json (Vietnamese)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations tabs.json (Chinese Simplified)

* New translations contextMenu.json (Chinese Simplified)

* New translations tabs.json (Ukrainian)

* New translations contextMenu.json (Ukrainian)

* New translations tabs.json (Chinese Traditional)

* New translations contextMenu.json (Chinese Traditional)

* New translations tabs.json (Spanish)

* New translations tabs.json (Catalan)

* New translations tabs.json (Dutch)

* New translations contextMenu.json (Spanish)

* New translations contextMenu.json (Catalan)

* New translations contextMenu.json (Dutch)

* New translations tabs.json (Dutch)

* New translations contextMenu.json (Basque)

* New translations contextMenu.json (Catalan)
2023-01-27 22:42:26 +01:00
xmflsct 023f66895d Fix #666 2023-01-27 21:54:48 +01:00
xmflsct 738194d108 Consolidate swipe to delete views 2023-01-27 18:44:48 +01:00
xmflsct aa5a607666
New Crowdin updates (#675)
* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Polish)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (German)

* New translations parse.json (Portuguese, Brazilian)

* New translations timeline.json (Portuguese, Brazilian)

* New translations mediaSelector.json (Portuguese, Brazilian)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations tabs.json (German)

* New translations tabs.json (Portuguese, Brazilian)

* New translations common.json (Portuguese, Brazilian)

* New translations common.json (Basque)

* New translations common.json (Basque)

* New translations instance.json (Basque)

* New translations parse.json (Basque)

* New translations relationship.json (Basque)

* New translations relationship.json (Basque)

* New translations timeline.json (Basque)

* New translations timeline.json (Catalan)

* New translations tabs.json (Catalan)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* 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 (French)

* New translations tabs.json (Polish)

* New translations tabs.json (Spanish)

* New translations tabs.json (Swedish)

* New translations tabs.json (Czech)

* New translations tabs.json (Dutch)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Russian)

* New translations tabs.json (Greek)

* New translations tabs.json (Basque)

* New translations contextMenu.json (French)

* New translations contextMenu.json (Spanish)

* New translations contextMenu.json (Catalan)

* New translations contextMenu.json (Czech)

* New translations contextMenu.json (German)

* New translations contextMenu.json (Greek)

* New translations contextMenu.json (Basque)

* New translations contextMenu.json (Italian)

* New translations contextMenu.json (Japanese)

* New translations contextMenu.json (Korean)

* New translations contextMenu.json (Dutch)

* New translations contextMenu.json (Polish)

* New translations contextMenu.json (Russian)

* New translations contextMenu.json (Swedish)

* New translations contextMenu.json (Ukrainian)

* New translations contextMenu.json (Chinese Simplified)

* New translations contextMenu.json (Chinese Traditional)

* New translations contextMenu.json (Vietnamese)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations tabs.json (Chinese Simplified)

* New translations contextMenu.json (Chinese Simplified)
2023-01-27 00:44:32 +01:00
xmflsct 7d5c9e906a Update contextMenu.json 2023-01-27 00:29:42 +01:00
xmflsct 05a46f23b9 Should improve #666
More optimisation still needed
2023-01-27 00:13:00 +01:00
xmflsct 4b8885ef2c Fix #670
Also on iOS
2023-01-26 23:55:48 +01:00
xmflsct 922d7c7917 Fix #668 2023-01-26 23:35:52 +01:00
xmflsct 653b588c29 Fix #613 2023-01-26 23:07:13 +01:00
xmflsct e8eb62e2d0 Refined filter view 2023-01-26 13:59:42 +01:00
xmflsct 2a806695ca
New Crowdin updates (#665)
* New translations tabs.json (Swedish)

* New translations contextMenu.json (Swedish)

* New translations contextMenu.json (Swedish)

* New translations instance.json (Japanese)

* New translations timeline.json (Japanese)

* New translations contextMenu.json (Japanese)

* New translations tabs.json (Japanese)

* New translations contextMenu.json (Korean)

* New translations tabs.json (Korean)

* New translations compose.json (French)

* New translations compose.json (German)

* New translations compose.json (Italian)

* New translations compose.json (Japanese)

* New translations compose.json (Korean)

* New translations compose.json (Chinese Simplified)

* New translations compose.json (Chinese Traditional)

* New translations compose.json (Vietnamese)

* New translations compose.json (Portuguese, Brazilian)

* New translations compose.json (Polish)

* New translations compose.json (Spanish)

* New translations compose.json (Swedish)

* New translations compose.json (Czech)

* New translations compose.json (Dutch)

* New translations compose.json (Catalan)

* New translations compose.json (Ukrainian)

* New translations compose.json (Russian)

* New translations compose.json (Greek)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* 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 (French)

* New translations tabs.json (Polish)

* New translations tabs.json (Spanish)

* New translations tabs.json (Swedish)

* New translations tabs.json (Czech)

* New translations tabs.json (Dutch)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Russian)

* New translations tabs.json (Greek)

* New translations tabs.json (Chinese Simplified)

* New translations common.json (Basque)

* New translations instance.json (Basque)

* New translations parse.json (Basque)

* New translations relationship.json (Basque)

* New translations timeline.json (Basque)

* New translations imageViewer.json (Basque)

* New translations announcements.json (Basque)

* New translations compose.json (Basque)

* New translations screens.json (Basque)

* New translations tabs.json (Basque)

* New translations mediaSelector.json (Basque)

* New translations emojis.json (Basque)

* New translations contextMenu.json (Basque)

* New translations accountSelection.json (Basque)
2023-01-26 01:14:24 +01:00
dependabot[bot] e417532d60
Bump ua-parser-js from 0.7.32 to 0.7.33 (#674)
Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.32 to 0.7.33.
- [Release notes](https://github.com/faisalman/ua-parser-js/releases)
- [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/changelog.md)
- [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.32...0.7.33)

---
updated-dependencies:
- dependency-name: ua-parser-js
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-26 00:59:21 +01:00
xmflsct d73857eef4 First step of adding filter editing support 2023-01-26 00:57:48 +01:00
xmflsct 2d91d1f7fb Fix react-native-svg default fill black 2023-01-25 00:29:36 +01:00
xmflsct 9d9c16df06 Bump packages
And deprecate react-native-feather
2023-01-25 00:15:46 +01:00
xmflsct ebc6d03c6a Fix url not encoded such as in CJK 2023-01-24 22:47:36 +01:00
xmflsct 82928f8611 Attempt to fix super long toots breaking maintain position 2023-01-24 22:24:55 +01:00
xmflsct f1b162a020 Added gif preference
https://github.com/mastodon/mastodon/pull/22706
2023-01-24 00:36:51 +01:00
xmflsct 47d5b02468 Fix #672
Removed image focus as different clients implement this differently
2023-01-23 23:05:25 +01:00
xmflsct 613cf1365c Fix 669 2023-01-22 18:17:57 +01:00
xmflsct 5cd83ae055 Improve my page's loading 2023-01-17 15:35:36 +01:00
xmflsct fb6a111c55 Fix #664 2023-01-17 12:57:37 +01:00
xmflsct d93c77c4ca Update yarn.lock 2023-01-16 22:56:58 +01:00
xmflsct a131b1277c Fix local content not loaded
With the new prepend approach
2023-01-16 22:52:30 +01:00
xmflsct c2a180f4f5 Fix popToTop dev warning 2023-01-16 22:36:49 +01:00
xmflsct adb7a765b4 Fix #663
Properly revoke token when actively logging out
2023-01-16 22:22:19 +01:00
xmflsct 196f51bfca Refine account switching
Part of #663
2023-01-16 22:11:41 +01:00
xmflsct 74e794a215 Fix some Sentry reported crashes 2023-01-16 18:56:15 +01:00
xmflsct 18ad22302d Attempt to fix #644 2023-01-16 18:50:18 +01:00
xmflsct 261987cac9
New Crowdin updates (#658)
* New translations timeline.json (Spanish)

* New translations timeline.json (Catalan)

* New translations timeline.json (Ukrainian)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* 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 (French)

* New translations tabs.json (Polish)

* New translations tabs.json (Spanish)

* New translations tabs.json (Swedish)

* New translations tabs.json (Czech)

* New translations tabs.json (Dutch)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Russian)

* New translations tabs.json (Greek)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Spanish)

* New translations tabs.json (Dutch)

* New translations tabs.json (Catalan)

* New translations tabs.json (German)

* New translations tabs.json (Chinese Simplified)
2023-01-16 14:58:47 +01:00
xmflsct e97eff25c5 Fix cached toot not replaced 2023-01-16 14:30:00 +01:00
xmflsct 3883c0307a Fix public page switching timeline not updating nav params 2023-01-16 14:20:36 +01:00
xmflsct 34c0bbf4bb Fix too thin images 2023-01-15 22:04:25 +01:00
xmflsct b52b529550 Fix conversation view when remote returns error 2023-01-15 21:51:27 +01:00
xmflsct f10d52cebc Use native loading spinner
The lib is not being maintained and the animation quality is bad
2023-01-15 20:34:22 +01:00
xmflsct 86c3e91439 Fixed Android's svg spans full width 2023-01-15 19:59:48 +01:00
xmflsct 9a289489fa Fix #661
The API does not support a better way to achieve this as suggested. Though the search API accepts a "following" param, and it will return data prioritising following accounts.
2023-01-15 19:38:45 +01:00
xmflsct 8814161e0e Improve toot page loading 2023-01-15 18:00:58 +01:00
xmflsct 0efb7e5b70 Fix #615 2023-01-15 13:40:12 +01:00
xmflsct e5744aba06 Try to fix #648
Also reported by other users
2023-01-14 16:58:01 +01:00
xmflsct e7ca5ba63d Fix #655 2023-01-14 16:29:28 +01:00
xmflsct 57f1ed62b5 Fix #657
No need for Android, as if permission was denied last time, the next time when requesting, permission would be checked again.
2023-01-14 16:20:37 +01:00
xmflsct 26d2c78517 Fix #653 2023-01-14 15:26:11 +01:00
xmflsct e5e74410d0 Fix #659 2023-01-14 15:21:31 +01:00
xmflsct 58c96c4c08 Fix Android does not support menu sub 2023-01-12 21:44:28 +01:00
xmflsct fa066daa59 Update HeaderConversation.tsx 2023-01-12 21:28:29 +01:00
xmflsct bebf4c7101 Update TextInput.tsx
There are still reports of text not wrapping #571
2023-01-12 21:24:45 +01:00
xmflsct 81b810496b No need to show initial toot in history
Nothing changed in there
2023-01-12 21:12:51 +01:00
xmflsct 2a19e1fc2a Fix #654 2023-01-12 21:04:50 +01:00
xmflsct a37f66d080 Fix unidentified mentions 2023-01-12 20:58:57 +01:00
xmflsct 03fd770a41 Hide useless cards 2023-01-12 20:28:43 +01:00
xmflsct 02a90e84f3 Wrong side of fixing crash 2023-01-12 20:17:26 +01:00
xmflsct 50f95900b6 Update Push.tsx 2023-01-11 23:34:02 +01:00
xmflsct c7602df08c
New translations compose.json (Catalan) (#651) 2023-01-11 22:55:35 +01:00
xmflsct 7f97908e23 Fix bugs 2023-01-11 22:54:24 +01:00
xmflsct 76d4bc754b Fix accounts array empty not init 2023-01-11 22:18:02 +01:00
xmflsct 30be3cdb15 Fix prepended toots not interactable 2023-01-11 21:51:28 +01:00
xmflsct 01c27d6a99 Fix tooot support broken 2023-01-11 21:35:50 +01:00
xmflsct e31ce3772a Do not auto refetch home timeline
Due to the new timeline position feature, auto refetch would shift the timeline and the user is not at the newest of the list anyway
2023-01-11 21:11:43 +01:00
xmflsct f93fe09783 Fix push wrong auth key format 2023-01-11 21:01:44 +01:00
xmflsct def4c5424e Reload image when the source is changed 2023-01-10 19:36:42 +01:00
xmflsct 8610be1caf Fix bugs 2023-01-10 14:56:13 +01:00
xmflsct 3de4212a65 Fix #646 2023-01-10 13:27:47 +01:00
xmflsct 1918274ec9 Update Toot.tsx 2023-01-10 00:52:50 +01:00
xmflsct d68ec113c6 Fix font size setting 2023-01-10 00:28:39 +01:00
xmflsct 89e2b46792 Merge branch 'main' of https://github.com/tooot-app/app 2023-01-09 22:53:34 +01:00
xmflsct a4e6540b50
New Crowdin updates (#642)
* New translations contextMenu.json (Chinese Traditional)

* New translations contextMenu.json (Polish)

* New translations contextMenu.json (Spanish)

* New translations contextMenu.json (Catalan)

* New translations contextMenu.json (Ukrainian)

* New translations contextMenu.json (Chinese Simplified)

* New translations contextMenu.json (German)

* New translations contextMenu.json (Dutch)
2023-01-09 22:53:23 +01:00
xmflsct a4e97ccb1c Fix warnings and errors 2023-01-09 22:28:53 +01:00
xmflsct b9c4b139f5 Tune queries 2023-01-09 19:18:48 +01:00
xmflsct be772f905d Added global scopes 2023-01-09 16:54:30 +01:00
xmflsct cd7e740ab1 Fix remove reply level not showing up correctly 2023-01-09 16:52:29 +01:00
xmflsct 1025d85ae5 Moving to JSON instead of FormData for oauth 2023-01-09 16:44:11 +01:00
xmflsct 1b2d9d144f Fix bugs 2023-01-09 10:11:44 +01:00
xmflsct 215534d0c8 Fix #605
Turns out to be much more complicated than expected. Finally got the app running through Browser Stack (thanks for their sponsoring!), realised the issue was related to an early attempt to create a build for F-Droid #50 which removed the Google Service. However for Android push, Google service is still required.
2023-01-09 00:55:29 +01:00
xmflsct cfa637b23d Fix Android build crashing 2023-01-08 21:53:05 +01:00
xmflsct a3b5a132c5 Added GoToSocial support
Fix #206
Fix https://github.com/superseriousbusiness/gotosocial/issues/825
2023-01-08 20:07:20 +01:00
xmflsct 43c0447418
New Crowdin updates (#641)
* New translations timeline.json (Korean)

* New translations contextMenu.json (Korean)

* New translations compose.json (Korean)

* New translations tabs.json (Korean)

* New translations contextMenu.json (German)

* New translations contextMenu.json (Italian)

* New translations contextMenu.json (Japanese)

* New translations contextMenu.json (Korean)

* New translations contextMenu.json (Chinese Simplified)

* New translations contextMenu.json (Chinese Traditional)

* New translations contextMenu.json (Vietnamese)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations contextMenu.json (French)

* New translations contextMenu.json (Polish)

* New translations contextMenu.json (Spanish)

* New translations contextMenu.json (Swedish)

* New translations contextMenu.json (Czech)

* New translations contextMenu.json (Dutch)

* New translations contextMenu.json (Catalan)

* New translations contextMenu.json (Ukrainian)

* New translations contextMenu.json (Russian)

* New translations contextMenu.json (Greek)

* New translations contextMenu.json (Chinese Simplified)
2023-01-08 18:12:13 +01:00
vitalyster 59a2d932e3
OAuth: send PKCE code verifier with token request (#640)
* OAuth: send PKCE code verifier with token request

* Prevents typescript's warning

Co-authored-by: xmflsct <me@xmflsct.com>
2023-01-08 18:06:30 +01:00
xmflsct 972ae46d45 Fix #604 2023-01-08 17:56:34 +01:00
xmflsct 4cadeb6a6f Add release notes for #271 2023-01-08 17:34:15 +01:00
xmflsct 0b1fdf59ca Added notes to #608
Not yet able to edit
2023-01-08 17:32:20 +01:00
xmflsct cc6740a7c0 Fix adding account bug 2023-01-08 17:07:47 +01:00
xmflsct 6ce78e94f8 Fix #271
Added follow as menu option
2023-01-08 16:59:35 +01:00
xmflsct 9e0e8db82a Fix Android start up crash
Maybe then we can run it in BrowserStack
2023-01-08 12:21:38 +01:00
xmflsct fb3f2e82d6 Fix Android bugs 2023-01-08 00:05:58 +01:00
xmflsct 2d9dc00683 Fix #633
https://github.com/expo/expo/issues/6864#issuecomment-678620290
2023-01-07 23:56:24 +01:00
xmflsct d6d0cc0d03 Fix Android crashing
Somehow get MMKV number would crash
2023-01-07 23:37:30 +01:00
xmflsct 7db8b26dd9 Simplify and improve pagination 2023-01-07 18:01:08 +01:00
xmflsct 44f8900902 Support broader fedi tag type 2023-01-07 16:41:14 +01:00
xmflsct 50332773c3 Fix #490
Support remembering timeline position in following
2023-01-07 16:27:40 +01:00
xmflsct fb9b7486d0 Use placeholder data instead of initial data 2023-01-07 13:08:33 +01:00
xmflsct 23a8c03be2 Fix when there is no newer content 2023-01-07 12:15:07 +01:00
xmflsct 88528f5293 Refine scroll after fetch newer 2023-01-07 12:10:41 +01:00
xmflsct 1704c0401c Fix remote toot level is not applied 2023-01-07 11:32:50 +01:00
xmflsct ea02561cdb With local caching and gradual prepending
For #490
2023-01-07 00:43:00 +01:00
xmflsct 70d57ed830 Fetching now works better
For #490
2023-01-06 22:58:01 +01:00
xmflsct c2aa78fef8 Fix highlighted toot cannot be actioned 2023-01-06 18:38:52 +01:00
xmflsct 5ce7d50f8f Make remote fetch more lazy
Sometime the local instance responses slower that would result in all the context are remote, which is not ideal.
2023-01-06 18:31:33 +01:00
xmflsct 3cac12fb9e Update Podfile.lock 2023-01-06 14:06:13 +01:00
xmflsct c7a472124c Revert "Try out FlashList"
This reverts commit 8406a57143.
2023-01-06 14:00:50 +01:00
xmflsct 8406a57143 Try out FlashList 2023-01-06 01:41:46 +01:00
xmflsct bd3046cc2f Updates 2023-01-06 01:08:27 +01:00
xmflsct c83a74d1c3 Fix status interactions 2023-01-06 01:01:10 +01:00
xmflsct feadcc019c Updates 2023-01-05 00:49:10 +01:00
xmflsct bb9fa0c752 Improved history diff 2023-01-04 23:12:18 +01:00
xmflsct 06324ee51a Believe #638 can be closed now! 2023-01-04 22:39:29 +01:00
xmflsct 62a6594f91 Try removing flipper 2023-01-04 01:20:34 +01:00
xmflsct 092bc5013a Merge branch 'main' of https://github.com/tooot-app/app 2023-01-04 00:14:34 +01:00
xmflsct ba5bc35a05
New Crowdin updates (#618)
* New translations tabs.json (Vietnamese)

* New translations instance.json (Vietnamese)

* New translations contextMenu.json (Vietnamese)

* New translations tabs.json (Vietnamese)

* New translations tabs.json (Catalan)

* New translations timeline.json (Spanish)

* New translations tabs.json (Spanish)

* New translations common.json (Ukrainian)

* New translations instance.json (Ukrainian)

* New translations parse.json (Ukrainian)

* New translations timeline.json (Ukrainian)

* New translations timeline.json (Ukrainian)

* New translations mediaSelector.json (Ukrainian)

* New translations accountSelection.json (Ukrainian)

* New translations common.json (Greek)

* New translations instance.json (Greek)

* New translations parse.json (Greek)

* New translations relationship.json (Greek)

* New translations timeline.json (Greek)

* New translations actions.json (Greek)

* New translations imageViewer.json (Greek)

* New translations announcements.json (Greek)

* New translations compose.json (Greek)

* New translations screens.json (Greek)

* New translations tabs.json (Greek)

* New translations mediaSelector.json (Greek)

* New translations emojis.json (Greek)

* New translations contextMenu.json (Greek)

* New translations accountSelection.json (Greek)

* New translations common.json (Greek)

* New translations instance.json (Greek)

* New translations parse.json (Greek)

* New translations actions.json (Greek)

* New translations imageViewer.json (Greek)

* New translations announcements.json (Greek)

* New translations compose.json (Greek)

* New translations screens.json (Greek)

* New translations mediaSelector.json (Greek)

* New translations emojis.json (Greek)

* New translations accountSelection.json (Greek)

* New translations tabs.json (Greek)

* New translations contextMenu.json (Greek)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Chinese Simplified)

* New translations relationship.json (Greek)

* New translations timeline.json (Greek)

* New translations contextMenu.json (Greek)

* New translations timeline.json (Greek)

* New translations tabs.json (Catalan)

* New translations timeline.json (German)

* New translations timeline.json (Italian)

* New translations timeline.json (Japanese)

* New translations timeline.json (Korean)

* New translations timeline.json (Chinese Simplified)

* New translations timeline.json (Chinese Traditional)

* New translations timeline.json (Vietnamese)

* New translations timeline.json (Portuguese, Brazilian)

* New translations timeline.json (French)

* New translations timeline.json (Spanish)

* New translations timeline.json (Swedish)

* New translations timeline.json (Dutch)

* New translations timeline.json (Catalan)

* New translations timeline.json (Ukrainian)

* New translations timeline.json (German)

* New translations timeline.json (Chinese Traditional)

* New translations timeline.json (Ukrainian)

* New translations timeline.json (Vietnamese)

* New translations timeline.json (Dutch)

* New translations timeline.json (Spanish)

* New translations timeline.json (Catalan)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* 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 (French)

* New translations tabs.json (Spanish)

* New translations tabs.json (Swedish)

* New translations tabs.json (Dutch)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Greek)

* New translations timeline.json (German)

* New translations timeline.json (Italian)

* New translations timeline.json (Japanese)

* New translations timeline.json (Korean)

* New translations timeline.json (Chinese Simplified)

* New translations timeline.json (Chinese Traditional)

* New translations timeline.json (Vietnamese)

* New translations timeline.json (Portuguese, Brazilian)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* 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 timeline.json (French)

* New translations tabs.json (French)

* New translations timeline.json (Polish)

* New translations timeline.json (Spanish)

* New translations tabs.json (Spanish)

* New translations timeline.json (Swedish)

* New translations tabs.json (Swedish)

* New translations timeline.json (Czech)

* New translations timeline.json (Dutch)

* New translations tabs.json (Dutch)

* New translations timeline.json (Catalan)

* New translations tabs.json (Catalan)

* New translations timeline.json (Ukrainian)

* New translations tabs.json (Ukrainian)

* New translations timeline.json (Russian)

* New translations timeline.json (Greek)

* New translations tabs.json (Greek)

* New translations timeline.json (Chinese Traditional)

* New translations tabs.json (Chinese Traditional)

* New translations timeline.json (Vietnamese)

* New translations tabs.json (Vietnamese)

* New translations timeline.json (German)

* New translations timeline.json (German)

* New translations timeline.json (Chinese Traditional)

* New translations timeline.json (Vietnamese)

* New translations timeline.json (Chinese Traditional)

* New translations timeline.json (Vietnamese)

* New translations contextMenu.json (German)

* New translations contextMenu.json (Japanese)

* New translations contextMenu.json (Korean)

* New translations contextMenu.json (Chinese Simplified)

* New translations contextMenu.json (Chinese Traditional)

* New translations contextMenu.json (Vietnamese)

* New translations contextMenu.json (French)

* New translations contextMenu.json (Polish)

* New translations contextMenu.json (Spanish)

* New translations contextMenu.json (Swedish)

* New translations timeline.json (Dutch)

* New translations contextMenu.json (Dutch)

* New translations contextMenu.json (Catalan)

* New translations contextMenu.json (Ukrainian)

* New translations contextMenu.json (Greek)

* New translations tabs.json (Ukrainian)

* New translations timeline.json (Spanish)

* New translations contextMenu.json (Spanish)

* New translations timeline.json (Catalan)

* New translations contextMenu.json (Catalan)

* New translations contextMenu.json (Vietnamese)

* New translations tabs.json (Vietnamese)

* New translations contextMenu.json (Ukrainian)

* New translations timeline.json (German)

* New translations timeline.json (Italian)

* New translations timeline.json (Japanese)

* New translations timeline.json (Korean)

* New translations timeline.json (Chinese Simplified)

* New translations timeline.json (Chinese Traditional)

* New translations timeline.json (Vietnamese)

* New translations timeline.json (Portuguese, Brazilian)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* 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 timeline.json (French)

* New translations tabs.json (French)

* New translations timeline.json (Spanish)

* New translations tabs.json (Spanish)

* New translations timeline.json (Polish)

* New translations tabs.json (Polish)

* New translations timeline.json (Czech)

* New translations timeline.json (Swedish)

* New translations tabs.json (Swedish)

* New translations tabs.json (Czech)

* New translations timeline.json (Dutch)

* New translations tabs.json (Dutch)

* New translations timeline.json (Catalan)

* New translations tabs.json (Catalan)

* New translations timeline.json (Ukrainian)

* New translations tabs.json (Ukrainian)

* New translations timeline.json (Russian)

* New translations tabs.json (Russian)

* New translations timeline.json (Greek)

* New translations tabs.json (Greek)

* New translations timeline.json (Chinese Traditional)

* New translations tabs.json (Chinese Traditional)

* New translations timeline.json (Vietnamese)

* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Vietnamese)

* New translations timeline.json (Dutch)

* New translations timeline.json (Spanish)

* New translations tabs.json (Spanish)

* New translations timeline.json (Catalan)

* New translations tabs.json (Catalan)

* New translations timeline.json (Ukrainian)

* New translations tabs.json (Ukrainian)

* New translations timeline.json (German)

* New translations tabs.json (German)

* New translations tabs.json (Ukrainian)

* New translations timeline.json (Polish)

* New translations timeline.json (Polish)

* New translations imageViewer.json (Polish)

* New translations compose.json (Polish)

* New translations screens.json (Polish)

* New translations tabs.json (Polish)

* New translations tabs.json (Dutch)

* New translations timeline.json (Swedish)

* New translations tabs.json (Swedish)

* New translations contextMenu.json (Swedish)

* New translations tabs.json (Polish)

* New translations tabs.json (Polish)

* New translations mediaSelector.json (Polish)

* New translations emojis.json (Polish)

* New translations contextMenu.json (Polish)

* New translations accountSelection.json (Polish)

* New translations timeline.json (Chinese Simplified)

* New translations contextMenu.json (Chinese Simplified)

* New translations tabs.json (Chinese Simplified)
2023-01-04 00:14:20 +01:00
xmflsct bd5e92cab3 Update build.yml 2023-01-04 00:08:58 +01:00
xmflsct 6b73485aae Bump packages 2023-01-04 00:06:37 +01:00
xmflsct 0bcd0c1725 Continue refine remote logic #638 2023-01-03 23:57:23 +01:00
xmflsct b067b9bdb1 Properly clean and reset navigators 2023-01-03 00:10:44 +01:00
xmflsct 4c6b8f0959 Fix toot action for #638 2023-01-02 23:18:22 +01:00
xmflsct 6dafbc96af Account actions working for #638 2023-01-02 02:08:12 +01:00
xmflsct 62df29a479 Update status.ts 2023-01-01 18:54:42 +01:00
xmflsct f3e1741629 Update updateStatusProperty.ts 2023-01-01 18:48:32 +01:00
xmflsct 2705b4b804 Simplify update toot logic 2023-01-01 18:37:05 +01:00
xmflsct 56d1090ca9 Actions working for #638 2023-01-01 17:20:35 +01:00
xmflsct ced71d6611 Reply working for #638 2023-01-01 16:44:55 +01:00
xmflsct ac9738d358 Remove flat list in compose view 2023-01-01 13:39:48 +01:00
xmflsct 554825a9ea Fix #636 2022-12-31 15:58:18 +01:00
xmflsct 13303c4269 Early demo of #638
Actions are not working yet
2022-12-31 15:53:02 +01:00
xmflsct eb385b8872 Fix bugs 2022-12-31 14:00:52 +01:00
xmflsct 65e9f41a3b Fix bugs 2022-12-31 12:56:10 +01:00
xmflsct f0734e52e7 Add string for #631 2022-12-31 02:08:33 +01:00
xmflsct 7ccfdc7562 Fix #631 2022-12-31 02:06:19 +01:00
xmflsct 4a25feb346 Fix #635 2022-12-31 00:31:25 +01:00
xmflsct b677c4b7ce Fix #558 #602 2022-12-31 00:07:28 +01:00
xmflsct 49a0e6d63e Remove base64 dep 2022-12-30 15:14:16 +01:00
xmflsct 0de7e84f58 Fix #632
No need to warn
2022-12-30 12:56:13 +01:00
xmflsct e13669af56 Support migrating from older database 2022-12-30 10:44:30 +01:00
xmflsct ca7309b862 Fix #601 #577 2022-12-29 23:38:44 +01:00
xmflsct 14b23ac480 Merge branch 'main' of https://github.com/tooot-app/app 2022-12-29 23:14:55 +01:00
John HU 1029cb6a67
Use lowercase via instead of Via (#621) 2022-12-29 23:14:40 +01:00
xmflsct a77e495b6b Fix admin options not showing up 2022-12-29 23:13:22 +01:00
xmflsct 43a98be2d9 Fix in case font size is missing 2022-12-29 23:03:23 +01:00
xmflsct c6aff79055 Fix public domain and API domain differ 2022-12-29 23:00:17 +01:00
xmflsct 53ea661d9a Use i18next's native RTL detection 2022-12-29 18:03:23 +01:00
xmflsct 892e6c6131 Updates 2022-12-29 01:10:50 +01:00
xmflsct 2a40043b2e Refine querying followed tags 2022-12-29 00:58:07 +01:00
xmflsct 4cddbb9bad Remove most React memorization
Though added memo for timeline components making them (almost) pure
2022-12-29 00:36:35 +01:00
xmflsct 1ea6aff328
619 restructure local storage (#628)
* To MMKV migration working

* POC migrated font size settings

* Moved settings to mmkv

* Fix typos

* Migrated contexts slice

* Migrated app slice

* POC instance emoji update

* Migrated drafts

* Migrated simple instance properties

* All migrated!

* Re-structure files

* Tolerant of undefined settings

* Can properly logging in and out including empty state
2022-12-28 23:41:36 +01:00
John HU 71ccb4a93c
Fix README.md build status badges (#622)
* Fix build status badges

Changes required for badges:
https://github.com/badges/shields/issues/8671

* Make special thanks section visually compact
2022-12-28 01:57:35 +01:00
xmflsct a40f0d9f82 Fix #620 #606 2022-12-26 01:06:33 +01:00
xmflsct 34f7218c34 Fix React key missing 2022-12-25 17:40:53 +01:00
xmflsct 21d6baa70d Fix babel 2022-12-24 14:46:39 +01:00
xmflsct f3b46b7e9c Commit yarn plugins 2022-12-24 12:59:07 +01:00
xmflsct ea5705a6de Enable corepack for yarn 3 2022-12-24 12:55:51 +01:00
xmflsct e1f951eb8c
New Crowdin updates (#599)
* New translations instance.json (Russian)

* New translations timeline.json (Russian)

* New translations actions.json (Russian)

* New translations announcements.json (Russian)

* New translations compose.json (Russian)

* New translations screens.json (Russian)

* New translations tabs.json (Russian)

* New translations emojis.json (Russian)

* New translations accountSelection.json (Russian)

* New translations contextMenu.json (German)

* New translations timeline.json (Spanish)

* New translations contextMenu.json (Spanish)

* New translations timeline.json (Catalan)

* New translations contextMenu.json (Catalan)

* New translations common.json (Spanish)

* New translations contextMenu.json (Spanish)

* New translations compose.json (Catalan)

* New translations timeline.json (Spanish)

* New translations compose.json (Spanish)

* New translations tabs.json (Spanish)

* New translations timeline.json (Catalan)

* New translations compose.json (Catalan)

* New translations tabs.json (Catalan)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* 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 (French)

* New translations tabs.json (Polish)

* New translations tabs.json (Spanish)

* New translations tabs.json (Swedish)

* New translations tabs.json (Czech)

* New translations tabs.json (Dutch)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Russian)

* New translations announcements.json (Catalan)

* New translations compose.json (Catalan)

* New translations tabs.json (Catalan)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* 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 (French)

* New translations tabs.json (Polish)

* New translations tabs.json (Spanish)

* New translations tabs.json (Swedish)

* New translations tabs.json (Czech)

* New translations tabs.json (Dutch)

* New translations tabs.json (Catalan)

* New translations tabs.json (Ukrainian)

* New translations tabs.json (Russian)

* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Chinese Traditional)

* New translations common.json (Polish)

* New translations instance.json (Polish)

* New translations parse.json (Polish)

* New translations relationship.json (Polish)

* New translations timeline.json (Polish)

* New translations imageViewer.json (Polish)

* New translations announcements.json (Polish)

* New translations compose.json (Polish)

* New translations contextMenu.json (Polish)

* New translations compose.json (Polish)

* New translations tabs.json (Polish)

* New translations tabs.json (Dutch)

* New translations tabs.json (Catalan)

* New translations tabs.json (Spanish)

* New translations tabs.json (Catalan)

* New translations compose.json (German)

* New translations compose.json (Italian)

* New translations compose.json (Japanese)

* New translations compose.json (Korean)

* New translations compose.json (Chinese Simplified)

* New translations compose.json (Chinese Traditional)

* New translations compose.json (Vietnamese)

* New translations compose.json (Portuguese, Brazilian)

* New translations tabs.json (German)

* New translations tabs.json (Italian)

* New translations tabs.json (Japanese)

* New translations tabs.json (Korean)

* New translations tabs.json (Chinese Simplified)

* New translations tabs.json (Chinese Traditional)

* New translations tabs.json (Vietnamese)

* New translations compose.json (French)

* New translations tabs.json (French)

* New translations compose.json (Polish)

* New translations tabs.json (Polish)

* New translations compose.json (Spanish)

* New translations tabs.json (Spanish)

* New translations compose.json (Swedish)

* New translations tabs.json (Swedish)

* New translations compose.json (Czech)

* New translations tabs.json (Czech)

* New translations compose.json (Dutch)

* New translations tabs.json (Dutch)

* New translations compose.json (Catalan)

* New translations tabs.json (Catalan)

* New translations compose.json (Ukrainian)

* New translations tabs.json (Ukrainian)

* New translations compose.json (Russian)

* New translations tabs.json (Russian)

* New translations tabs.json (Portuguese, Brazilian)

* New translations contextMenu.json (German)

* New translations contextMenu.json (Italian)

* New translations contextMenu.json (Japanese)

* New translations contextMenu.json (Korean)

* New translations contextMenu.json (Chinese Simplified)

* New translations contextMenu.json (Chinese Traditional)

* New translations contextMenu.json (Vietnamese)

* New translations contextMenu.json (Portuguese, Brazilian)

* New translations tabs.json (German)

* New translations tabs.json (Chinese Traditional)

* New translations contextMenu.json (French)

* New translations contextMenu.json (Polish)

* New translations contextMenu.json (Spanish)

* New translations contextMenu.json (Swedish)

* New translations contextMenu.json (Czech)

* New translations tabs.json (Dutch)

* New translations contextMenu.json (Dutch)

* New translations contextMenu.json (Catalan)

* New translations timeline.json (Ukrainian)

* New translations tabs.json (Ukrainian)

* New translations contextMenu.json (Ukrainian)

* New translations contextMenu.json (Russian)

* New translations contextMenu.json (Ukrainian)

* New translations tabs.json (Spanish)

* New translations contextMenu.json (Spanish)

* New translations tabs.json (Catalan)

* New translations contextMenu.json (Catalan)

* New translations contextMenu.json (Chinese Simplified)

* New translations tabs.json (Chinese Simplified)
2022-12-24 02:25:16 +01:00
xmflsct 219358cf54 Fix #590 2022-12-24 02:13:24 +01:00
xmflsct e27bf7407b Fix #616 2022-12-24 01:59:18 +01:00
xmflsct b6045e5121 Remove most React memo
Maybe would solve iOS out of memory crashes
2022-12-24 01:18:20 +01:00
xmflsct 1e0e8842db Use new Sentry tracing 2022-12-24 01:07:08 +01:00
xmflsct 64b367a247 Fix #614 2022-12-23 20:02:44 +01:00
xmflsct 3594500b3e Fix #610 2022-12-23 18:49:50 +01:00
xmflsct f3c40e9486 Fix #611 2022-12-23 18:19:14 +01:00
xmflsct 57e1206faf Upgrade to yarn 3 2022-12-23 17:47:01 +01:00
xmflsct e32125ad17 Update i18next type 2022-12-23 15:53:40 +01:00
xmflsct b388853429 Refine types for #600 2022-12-22 18:38:04 +01:00
xmflsct 39ab9059d9 Fix #600 2022-12-22 01:21:51 +01:00
614 changed files with 36873 additions and 28352 deletions

View File

@ -7,24 +7,20 @@ on:
jobs:
build-ios:
runs-on: macos-12
runs-on: macos-14
steps:
- name: -- Step 0 -- Extract branch name
uses: tj-actions/branch-names@v6
- uses: tj-actions/branch-names@v8
id: branch
- name: -- Step 1 -- Checkout code
uses: actions/checkout@v3
- name: -- Step 2 -- Setup node
uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: -- Step 3 -- Install node dependencies
run: yarn install
- name: -- Step 4 -- Install ruby dependencies
run: bundle install
- name: -- Step 5 -- Run fastlane
- run: corepack enable
- run: yarn install
- run: bundle install
- run: yarn app:build ios
env:
DEVELOPER_DIR: /Applications/Xcode_14.1.app/Contents/Developer
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
ENVIRONMENT: ${{ steps.branch.outputs.current_branch }}
SENTRY_ENVIRONMENT: ${{ steps.branch.outputs.current_branch }}
LC_ALL: en_US.UTF-8
@ -40,30 +36,24 @@ jobs:
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY }}
GH_PAT_GET_RELEASE: ${{ secrets.GITHUB_TOKEN }}
run: yarn app:build ios
build-android:
runs-on: macos-12
runs-on: macos-14
steps:
- name: -- Step 0 -- Extract branch name
uses: tj-actions/branch-names@v6
- uses: tj-actions/branch-names@v8
id: branch
- name: -- Step 1 -- Checkout code
uses: actions/checkout@v3
- name: -- Step 2 -- Setup node
uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: -- Step 3 -- Setup Java
uses: actions/setup-java@v3
- uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '11'
- name: -- Step 4 -- Install node dependencies
run: yarn install
- name: -- Step 5 -- Install ruby dependencies
run: bundle install
- name: -- Step 6 -- Run fastlane
java-version: '17'
- run: corepack enable
- run: yarn install
- run: bundle install
- run: yarn app:build android
env:
ENVIRONMENT: ${{ steps.branch.outputs.current_branch }}
SENTRY_ENVIRONMENT: ${{ steps.branch.outputs.current_branch }}
@ -75,31 +65,25 @@ jobs:
ANDROID_KEYSTORE_KEY_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_KEY_PASSWORD }}
SUPPLY_JSON_KEY_DATA: ${{ secrets.SUPPLY_JSON_KEY_DATA }}
GH_PAT_GET_RELEASE: ${{ secrets.GITHUB_TOKEN }}
run: yarn app:build android
create-release:
runs-on: macos-12
runs-on: macos-14
needs: [build-ios, build-android]
steps:
- name: -- Step 0 -- Extract branch name
uses: tj-actions/branch-names@v6
- uses: tj-actions/branch-names@v8
id: branch
- name: -- Step 1 -- Checkout code
uses: actions/checkout@v3
- name: -- Step 2 -- Setup node
uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: -- Step 3 -- Setup Java
uses: actions/setup-java@v3
- uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: '11'
- name: -- Step 4 -- Install node dependencies
run: yarn install
- name: -- Step 5 -- Install ruby dependencies
run: bundle install
- name: -- Step 6 -- Run fastlane
java-version: '17'
- run: corepack enable
- run: yarn install
- run: bundle install
- run: yarn app:build release
env:
ENVIRONMENT: ${{ steps.branch.outputs.current_branch }}
SENTRY_ENVIRONMENT: ${{ steps.branch.outputs.current_branch }}
@ -113,4 +97,3 @@ jobs:
ANDROID_KEYSTORE_ALIAS: ${{ secrets.ANDROID_KEYSTORE_ALIAS }}
ANDROID_KEYSTORE_KEY_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_KEY_PASSWORD }}
FL_GITHUB_RELEASE_API_BEARER: ${{ secrets.GITHUB_TOKEN }}
run: yarn app:build release

23
.gitignore vendored
View File

@ -32,6 +32,7 @@ DerivedData
*.xcuserstate
project.xcworkspace
ios/.xcode.env.local
ios/containers
# Android/IntelliJ
#
@ -42,6 +43,8 @@ local.properties
*.iml
*.hprof
.cxx/
*.keystore
!debug.keystore
# node.js
#
@ -49,12 +52,6 @@ node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# Bundle artifacts
*.jsbundle
@ -66,4 +63,16 @@ buck-out/
web-build/
dist/
# @end expo-cli
# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*
# @end expo-cli
# yarn 3
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

2
.nvmrc
View File

@ -1 +1 @@
16
20

View File

@ -1,7 +1,7 @@
diff --git a/node_modules/@types/react-native-share-menu/index.d.ts b/node_modules/@types/react-native-share-menu/index.d.ts
index f52822c..ee98565 100755
--- a/node_modules/@types/react-native-share-menu/index.d.ts
+++ b/node_modules/@types/react-native-share-menu/index.d.ts
diff --git a/index.d.ts b/index.d.ts
index f52822c8bed928f387baf90fdb7342c7416a775a..6d9d480d18342832c4b07af2b10f4a63ff538e7b 100755
--- a/index.d.ts
+++ b/index.d.ts
@@ -5,11 +5,9 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 3.7
@ -17,12 +17,18 @@ index f52822c..ee98565 100755
export type ShareCallback = (share?: ShareData) => void;
@@ -28,7 +26,7 @@ interface ShareMenuReactView {
dismissExtension(error?: string): void;
openApp(): void;
continueInApp(extraData?: object): void;
@@ -25,10 +23,10 @@ interface ShareMenu {
}
interface ShareMenuReactView {
- dismissExtension(error?: string): void;
- openApp(): void;
- continueInApp(extraData?: object): void;
- data(): Promise<{mimeType: string, data: string}>;
+ data(): Promise<{data: {mimeType: string; data: string}[]}>;
+ dismissExtension(error?: string): void
+ openApp(): void
+ continueInApp(extraData?: object): void
+ data(): Promise<{ data: { mimeType: string; data: string }[] }>
}
export const ShareMenuReactView: ShareMenuReactView;

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()

View File

@ -1,7 +1,7 @@
diff --git a/node_modules/react-native-share-menu/android/build.gradle b/node_modules/react-native-share-menu/android/build.gradle
index 9557fdb..ebdeb6f 100644
--- a/node_modules/react-native-share-menu/android/build.gradle
+++ b/node_modules/react-native-share-menu/android/build.gradle
diff --git a/android/build.gradle b/android/build.gradle
index 9557fdbf2fbf97b7f7aeaf7ce86d301a8ced213d..ebdeb6f4de7846d3241101001755595c52a4b05e 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.library'
@ -19,10 +19,10 @@ index 9557fdb..ebdeb6f 100644
versionCode 1
versionName "1.0"
ndk {
diff --git a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
index f42bce6..ee36062 100644
--- a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
+++ b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
diff --git a/ios/ReactShareViewController.swift b/ios/ReactShareViewController.swift
index f42bce6ce7e3f48a7ddc83f3366b68fd0664b1a0..ee360622b1d03cc9661c78c6f210b84c3b19a725 100644
--- a/ios/ReactShareViewController.swift
+++ b/ios/ReactShareViewController.swift
@@ -13,7 +13,7 @@ class ReactShareViewController: ShareViewController, RCTBridgeDelegate, ReactSha
func sourceURL(for bridge: RCTBridge!) -> URL! {
#if DEBUG
@ -32,10 +32,10 @@ index f42bce6..ee36062 100644
#else
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
diff --git a/node_modules/react-native-share-menu/ios/ShareViewController.swift b/node_modules/react-native-share-menu/ios/ShareViewController.swift
index 12d8c92..64aa72b 100644
--- a/node_modules/react-native-share-menu/ios/ShareViewController.swift
+++ b/node_modules/react-native-share-menu/ios/ShareViewController.swift
diff --git a/ios/ShareViewController.swift b/ios/ShareViewController.swift
index 12d8c92dda20fabd9e7b55fec57b3d867414063c..8a1db0de285b18a9358a10b2ca8293a8c7d56a8e 100644
--- a/ios/ShareViewController.swift
+++ b/ios/ShareViewController.swift
@@ -19,8 +19,8 @@ class ShareViewController: SLComposeServiceViewController {
var hostAppUrlScheme: String?
var sharedItems: [Any] = []
@ -78,7 +78,7 @@ index 12d8c92..64aa72b 100644
override func configurationItems() -> [Any]! {
// To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
return []
@@ -238,11 +235,10 @@ class ShareViewController: SLComposeServiceViewController {
@@ -238,7 +235,7 @@ class ShareViewController: SLComposeServiceViewController {
func completeRequest() {
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
@ -87,7 +87,3 @@ index 12d8c92..64aa72b 100644
}
func cancelRequest() {
extensionContext!.cancelRequest(withError: NSError())
}
-
}

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

File diff suppressed because one or more lines are too long

7
.yarnrc.yml Normal file
View File

@ -0,0 +1,7 @@
compressionLevel: mixed
enableGlobalCache: false
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.1.0.cjs

View File

@ -1,6 +1,13 @@
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 'cocoapods'
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

View File

@ -1,48 +1,47 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
CFPropertyList (3.0.6)
rexml
activesupport (6.1.7)
activesupport (7.0.4.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.1)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.653.0)
aws-sdk-core (3.166.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-eventstream (1.3.0)
aws-partitions (1.887.0)
aws-sdk-core (3.191.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.59.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (1.77.0)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.117.1)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-s3 (1.143.0)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.2)
aws-sigv4 (~> 1.8)
aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
cocoapods (1.11.3)
cocoapods (1.14.3)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.11.3)
cocoapods-core (= 1.14.3)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.4.0, < 2.0)
cocoapods-downloader (>= 2.1, < 3.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.4.0, < 2.0)
cocoapods-trunk (>= 1.6.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
@ -50,10 +49,10 @@ GEM
gh_inspector (~> 1.0)
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (>= 1.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0)
cocoapods-core (1.11.3)
activesupport (>= 5.0, < 7)
ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.23.0, < 2.0)
cocoapods-core (1.14.3)
activesupport (>= 5.0, < 8)
addressable (~> 2.8)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
@ -63,7 +62,7 @@ GEM
public_suffix (~> 4.0)
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.6.3)
cocoapods-downloader (2.1)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
@ -75,19 +74,18 @@ GEM
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
concurrent-ruby (1.1.10)
concurrent-ruby (1.2.2)
declarative (0.0.20)
digest-crc (0.6.4)
digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
domain_name (0.6.20240107)
dotenv (2.8.1)
emoji_regex (3.2.3)
escape (0.0.4)
ethon (0.15.0)
ethon (0.16.0)
ffi (>= 1.15.0)
excon (0.93.1)
faraday (1.10.2)
excon (0.109.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@ -115,8 +113,8 @@ GEM
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.210.1)
fastimage (2.3.0)
fastlane (2.219.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@ -135,20 +133,22 @@ GEM
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-env (>= 1.6.0, < 2.0.0)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (~> 2.0.0)
multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
optparse (~> 0.1.1)
optparse (>= 0.1.1)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
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-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
@ -156,17 +156,17 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-json (1.1.0)
fastlane-plugin-sentry (1.14.0)
fastlane-plugin-sentry (1.15.0)
os (~> 1.1, >= 1.1.4)
fastlane-plugin-versioning_android (0.1.0)
fastlane-plugin-versioning_android (0.1.1)
fastlane-plugin-yarn (1.2)
ffi (1.15.5)
ffi (1.16.3)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.29.0)
google-apis-core (>= 0.9.0, < 2.a)
google-apis-core (0.9.1)
google-apis-androidpublisher_v3 (0.54.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.3)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@ -174,31 +174,29 @@ GEM
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
webrick
google-apis-iamcredentials_v1 (0.15.0)
google-apis-core (>= 0.9.0, < 2.a)
google-apis-playcustomapp_v1 (0.12.0)
google-apis-core (>= 0.9.1, < 2.a)
google-apis-storage_v1 (0.19.0)
google-apis-core (>= 0.9.0, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-apis-iamcredentials_v1 (0.17.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.31.0)
google-apis-core (>= 0.11.0, < 2.a)
google-cloud-core (1.6.1)
google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.3.0)
google-cloud-storage (1.43.0)
google-cloud-errors (1.3.1)
google-cloud-storage (1.47.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
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)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.3.0)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
@ -208,64 +206,59 @@ GEM
httpclient (2.8.3)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
jmespath (1.6.1)
json (2.6.2)
jwt (2.5.0)
memoist (0.16.2)
mini_magick (4.11.0)
mini_mime (1.1.2)
minitest (5.16.3)
jmespath (1.6.2)
json (2.7.1)
jwt (2.7.1)
mini_magick (4.12.0)
mini_mime (1.1.5)
minitest (5.18.0)
molinillo (0.8.0)
multi_json (1.15.0)
multipart-post (2.0.0)
multipart-post (2.3.0)
nanaimo (0.3.0)
nap (1.1.0)
naturally (2.2.1)
netrc (0.11.0)
optparse (0.1.1)
optparse (0.4.0)
os (1.1.4)
plist (3.6.0)
plist (3.7.1)
public_suffix (4.0.7)
rake (13.0.6)
rake (13.1.0)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.2.5)
rexml (3.2.6)
rouge (2.0.7)
ruby-macho (2.5.1)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
signet (0.17.0)
signet (0.18.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
simctl (1.6.10)
CFPropertyList
naturally
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-screen (0.8.2)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
typhoeus (1.4.0)
typhoeus (1.4.1)
ethon (>= 0.9.0)
tzinfo (2.0.5)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (1.8.0)
webrick (1.7.0)
unicode-display_width (2.5.0)
word_wrap (1.0.0)
xcodeproj (1.22.0)
xcodeproj (1.24.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
@ -276,18 +269,21 @@ GEM
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
zeitwerk (2.6.1)
PLATFORMS
arm64-darwin-22
DEPENDENCIES
cocoapods
activesupport (>= 6.1.7.5, < 7.1.0)
cocoapods (>= 1.13, < 1.15)
fastlane
fastlane-plugin-json
fastlane-plugin-sentry
fastlane-plugin-versioning_android
fastlane-plugin-yarn
RUBY VERSION
ruby 3.1.2p20
BUNDLED WITH
2.3.24

View File

@ -1,38 +1,30 @@
# [tooot](https://tooot.app/) app for Mastodon
# [tooot](https://tooot.app/) app for Mastodon compatible platforms
[![GPL-3.0](https://img.shields.io/github/license/tooot-app/push)](LICENSE) ![GitHub issues](https://img.shields.io/github/issues/tooot-app/app) ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/tooot-app/app?include_prereleases) [![Crowdin](https://badges.crowdin.net/tooot/localized.svg)](https://crowdin.tooot.app/project/tooot)
![GitHub Workflow Status (candidate)](https://img.shields.io/github/workflow/status/tooot-app/app/build/candidate?label=build%20candidate) ![GitHub Workflow Status (release)](https://img.shields.io/github/workflow/status/tooot-app/app/build/release?label=build%20release)
![GitHub Workflow Status (candidate)](https://img.shields.io/github/actions/workflow/status/tooot-app/app/build.yml?branch=candidate&label=build%20candidate) ![GitHub Workflow Status (release)](https://img.shields.io/github/actions/workflow/status/tooot-app/app/build.yml?branch=release&label=build%20release)
## Contribute to translation
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
[@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
[@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
[@hellojaccc](https://github.com/hellojaccc) for Korean translation
[@jan-vandenberg](https://crowdin.com/profile/jan-vandenberg) for Dutch translation
[@luizpicolo](https://github.com/luizpicolo) for Brazilian Portuguese
[@janlindblom](https://github.com/janlindblom) for Swedish
[@ihoryan](https://crowdin.com/profile/ihoryan) for Ukrainian
[@duy@mas.to](https://mas.to/@duy) for Vietnamese translation
[@jimmyorz](https://github.com/jimmyorz) for Traditional Chinese translation
[@jk@mastodon.social](https://mastodon.social/@jk) for the famous Mastodon boop sound
- [@a_mento](https://crowdin.com/profile/a_mento) for Basques translation
- [@dzmitry.zubialevich](https://crowdin.com/profile/dzmitry.zubialevich) for Belarusian translation
- [@amrtf](https://crowdin.com/profile/amrtf) for Catalan and Spanish 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
- [@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
- [@jan-vandenberg](https://crowdin.com/profile/jan-vandenberg) for Dutch translation
- [@gaute](https://gauteweb.net/) for Norwegian translation
- [@MStankiewiczOfficial](https://crowdin.com/profile/MStankiewiczOfficial) for Polish translation
- [@luizpicolo](https://github.com/luizpicolo) for Brazilian Portuguese
- [@janlindblom](https://github.com/janlindblom) for Swedish
- [@ihoryan](https://crowdin.com/profile/ihoryan) for Ukrainian
- [@duy@mas.to](https://mas.to/@duy) for Vietnamese translation
- [@jimmyorz](https://github.com/jimmyorz) for Traditional Chinese translation
- [@jk@mastodon.social](https://mastodon.social/@jk) for the famous Mastodon boop sound

View File

@ -1,55 +0,0 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
lib_deps = []
create_aar_targets(glob(["libs/*.aar"]))
create_jar_targets(glob(["libs/*.jar"]))
android_library(
name = "all-libs",
exported_deps = lib_deps,
)
android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)
android_build_config(
name = "build_config",
package = "com.xmflsct.app.tooot",
)
android_resource(
name = "res",
package = "com.xmflsct.app.tooot",
res = "src/main/res",
)
android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)

View File

@ -1,215 +1,91 @@
apply plugin: "com.android.application"
import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
apply plugin: 'com.google.gms.google-services'
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation. If none specified and
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
* // default. Can be overridden with ENTRY_FILE environment variable.
* entryFile: "index.android.js",
*
* // https://reactnative.dev/docs/performance#enable-the-ram-format
* bundleCommand: "ram-bundle",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
* 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.
*/
project.ext.react = [
enableHermes: true,
]
apply from: new File(["node", "--print", "require.resolve('react-native/package.json')"].execute().text.trim(), "../react.gradle")
react {
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..'
// root = file("../")
// The folder where the react-native NPM package is. Default is ../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
// 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
// cliFile = file("../node_modules/react-native/cli.js")
/* Variants */
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
// debuggableVariants = ["liteDebug", "prodDebug"]
/* Bundling */
// A list containing the node command and its flags. Default is just 'node'.
// nodeExecutableAndArgs = ["node"]
//
// The command to run when bundling. By default is 'bundle'
// bundleCommand = "ram-bundle"
//
// The path to the CLI configuration file. Default is empty.
// bundleConfig = file(../rn-cli.config.js)
//
// The name of the generated asset file containing your JS bundle
// bundleAssetName = "MyApplication.android.bundle"
//
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
// entryFile = file("../js/MyApplication.android.js")
//
// A list of extra flags to pass to the 'bundle' commands.
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
// extraPackagerArgs = []
/* Hermes Commands */
// The hermes compiler command to run. By default it is 'hermesc'
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]
}
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
*/
def enableProguardInReleaseBuilds = false
/**
* The preferred build flavor of JavaScriptCore.
* The preferred build flavor of JavaScriptCore (JSC)
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Whether to enable the Hermes VM.
*
* This should be set on project.ext.react and mirrored here. If it is not set
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced.
*/
def enableHermes = project.ext.react.get("enableHermes", true);
/**
* Architectures to build native code for.
*/
def reactNativeArchitectures() {
def value = project.getProperties().get("reactNativeArchitectures")
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
android {
ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
namespace "com.xmflsct.app.tooot"
defaultConfig {
applicationId 'com.xmflsct.app.tooot'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 50
versionName "0.2"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) {
// We configure the CMake build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
cmake {
arguments "-DPROJECT_BUILD_DIR=$buildDir",
"-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
"-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
"-DNODE_MODULES_DIR=$rootDir/../node_modules",
"-DANDROID_STL=c++_shared"
}
}
if (!enableSeparateBuildPerCPUArchitecture) {
ndk {
abiFilters (*reactNativeArchitectures())
}
}
}
}
if (isNewArchitectureEnabled()) {
// We configure the CMake build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
cmake {
path "$projectDir/src/main/jni/CMakeLists.txt"
}
}
def reactAndroidProjectDir = project(':ReactAndroid').projectDir
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
into("$buildDir/react-ndk/exported")
}
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
into("$buildDir/react-ndk/exported")
}
afterEvaluate {
// If you wish to add a custom TurboModule or component locally,
// you should uncomment this line.
// preBuild.dependsOn("generateCodegenArtifactsFromSchema")
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
// Due to a bug inside AGP, we have to explicitly set a dependency
// between configureCMakeDebug* tasks and the preBuild tasks.
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild)
configureCMakeDebug.dependsOn(preDebugBuild)
reactNativeArchitectures().each { architecture ->
tasks.findByName("configureCMakeDebug[${architecture}]")?.configure {
dependsOn("preDebugBuild")
}
tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure {
dependsOn("preReleaseBuild")
}
}
}
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include (*reactNativeArchitectures())
}
}
signingConfigs {
debug {
@ -231,32 +107,9 @@ android {
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 {
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.3.0") {
force = true
}
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
@ -282,58 +135,16 @@ dependencies {
}
}
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
implementation("com.facebook.react:flipper-integration")
if (enableHermes) {
//noinspection GradleDynamicVersion
implementation("com.facebook.react:hermes-engine:+") { // From node_modules
exclude group:'com.facebook.fbjni'
}
if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
implementation jscFlavor
}
}
if (isNewArchitectureEnabled()) {
// If new architecture is enabled, we let you build RN from source
// Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
// This will be applied to all the imported transitive dependency.
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute(module("com.facebook.react:react-native"))
.using(project(":ReactAndroid"))
.because("On New Architecture we're building React Native from source")
substitute(module("com.facebook.react:hermes-engine"))
.using(project(":ReactAndroid:hermes-engine"))
.because("On New Architecture we're building Hermes from source")
}
}
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.implementation
into 'libs'
}
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute().text.trim(), "../native_modules.gradle");
applyNativeModulesAppBuildGradle(project)
def isNewArchitectureEnabled() {
// To opt-in for the New Architecture, you can either:
// - Set `newArchEnabled` to true inside the `gradle.properties` file
// - Invoke gradle with `-newArchEnabled=true`
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}

View File

@ -1,19 +0,0 @@
"""Helper definitions to glob .aar and .jar targets"""
def create_aar_targets(aarfiles):
for aarfile in aarfiles:
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
lib_deps.append(":" + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
def create_jar_targets(jarfiles):
for jarfile in jarfiles:
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
lib_deps.append(":" + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)

View File

@ -0,0 +1,55 @@
{
"project_info": {
"project_number": "661638997772",
"project_id": "xmflsct-mastodon-app",
"storage_bucket": "xmflsct-mastodon-app.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:661638997772:android:4fd02851f757f8fa9f8b29",
"android_client_info": {
"package_name": "com.xmflsct.app.tooot"
}
},
"oauth_client": [
{
"client_id": "661638997772-erabggnp958v10r0tvsrh3pg880qnvqn.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "com.xmflsct.app.tooot",
"certificate_hash": "53162f104230ee8b7b1372e4f378e2b9607ca16f"
}
},
{
"client_id": "661638997772-6aiqk97aema0rt280i7nfar3ha2mlgno.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDUw4s-mhQsHvs4hdIsldsi68ZIygM5MC4"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "661638997772-6aiqk97aema0rt280i7nfar3ha2mlgno.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "661638997772-65g8ce369ugck3ii4ulk6jhb3ijg51kl.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "com.xmflsct.app.tooot",
"app_store_id": "1549772269"
}
}
]
}
}
}
],
"configuration_version": "1"
}

View File

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

View File

@ -1,70 +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.react.ReactFlipperPlugin;
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;
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 ReactFlipperPlugin());
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

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" package="com.xmflsct.app.tooot">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
@ -9,11 +8,12 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:requestLegacyExternalStorage="true">
<!-- [Custom] Expo Notifications -->
<meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/ic_stat_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>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>

View File

@ -1,53 +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.ReactRootView;
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}. There the RootView is created and
* you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
* (Paper).
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegateWrapper(this, new MainActivityDelegate(this, getMainComponentName()));
}
public static class MainActivityDelegate extends ReactActivityDelegate {
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
super(activity, mainComponentName);
}
@Override
protected ReactRootView createRootView() {
ReactRootView reactRootView = new ReactRootView(getContext());
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
return reactRootView;
}
@Override
protected boolean isConcurrentRootEnabled() {
// If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
// More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}
}
}

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,112 +0,0 @@
package com.xmflsct.app.tooot;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import androidx.annotation.NonNull;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import expo.modules.ApplicationLifecycleDispatcher;
import expo.modules.ReactNativeHostWrapper;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import com.facebook.react.bridge.JSIModulePackage; // <- react-native-reanimated-v2
import com.swmansion.reanimated.ReanimatedJSIModulePackage; // <- react-native-reanimated-v2
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHostWrapper(
this,
new ReactNativeHost(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 // <- react-native-reanimated-v2
protected JSIModulePackage getJSIModulePackage() {
return new ReanimatedJSIModulePackage();
}
});
@Override
public ReactNativeHost getReactNativeHost() {
// if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// return mNewArchitectureNativeHost;
// } else {
// return mReactNativeHost;
// }
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
// If you opted-in for the New Architecture, we enable the TurboModule system
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
ApplicationLifecycleDispatcher.onApplicationCreate(this);
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.xmflsct.app.tooot.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}

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 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "31.0.0"
buildToolsVersion = "34.0.0"
minSdkVersion = 21
compileSdkVersion = 31
targetSdkVersion = 31
kotlinVersion = '1.6.10'
if (System.properties['os.arch'] == "aarch64") {
// For M1 Users we need to use the NDK 24 which added support for aarch64
ndkVersion = "24.0.8215888"
} else {
// Otherwise we default to the side-by-side NDK version from AGP.
ndkVersion = "21.4.7075529"
}
compileSdkVersion = 34
targetSdkVersion = 34
ndkVersion = "25.1.8937393"
kotlinVersion = '1.8.0'
}
repositories {
google()
@ -22,30 +13,11 @@ buildscript {
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:7.2.1")
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("de.undercouch:gradle-download-task:5.0.1")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.google.gms:google-services:4.3.14'
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
}
}
allprojects {
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute().text.trim(), "../android"))
}
maven {
// Android JSC is installed from npm
url(new File(["node", "--print", "require.resolve('jsc-android/package.json')"].execute().text.trim(), "../dist"))
}
google()
mavenCentral()
jcenter()
maven { url 'https://www.jitpack.io' }
}
}
apply plugin: "com.facebook.react.rootproject"

View File

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

Binary file not shown.

View File

@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
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
zipStorePath=wrapper/dists

81
android/gradlew vendored
View File

@ -1,7 +1,7 @@
#!/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");
# 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
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
@ -37,13 +79,11 @@ do
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# 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"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -73,6 +113,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@ -89,22 +130,29 @@ location of your Java installation."
fi
else
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
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
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 ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | 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" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@ -122,7 +170,9 @@ fi
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
@ -147,16 +197,27 @@ if "$cygwin" || "$msys" ; then
done
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;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
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.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
@ -183,4 +244,4 @@ eval "set -- $(
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
exec "$JAVACMD" "$@"

17
android/gradlew.bat vendored
View File

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

View File

@ -1,17 +1,10 @@
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()
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)
include ':app'
includeBuild('../node_modules/react-native-gradle-plugin')
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
include(":ReactAndroid")
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
include(":ReactAndroid:hermes-engine")
project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
}
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile())

View File

@ -8,6 +8,7 @@ export default (): ExpoConfig => ({
slug: 'tooot',
scheme: 'tooot',
version,
// @ts-ignore
extra: { environment: process.env.ENVIRONMENT },
privacy: 'hidden',
ios: {
@ -15,8 +16,9 @@ export default (): ExpoConfig => ({
},
android: {
package: 'com.xmflsct.app.tooot',
permissions: ['CAMERA', 'VIBRATE'],
blockedPermissions: ['USE_BIOMETRIC', 'USE_FINGERPRINT']
permissions: ['NOTIFICATIONS', 'CAMERA', 'VIBRATE'],
blockedPermissions: ['USE_BIOMETRIC', 'USE_FINGERPRINT'],
googleServicesFile: './android/app/google-services.json'
},
plugins: [
[

View File

@ -1,47 +1,27 @@
module.exports = function (api) {
api.cache(true)
const plugins = [
'@babel/plugin-proposal-optional-chaining',
[
'module-resolver',
{
root: ['./'],
alias: {
'@assets': './assets',
'@root': './src',
'@api': './src/api',
'@helpers': './src/helpers',
'@components': './src/components',
'@screens': './src/screens',
'@utils': './src/utils'
}
}
],
'react-native-reanimated/plugin'
]
if (
process.env.NODE_ENV === 'production' ||
process.env.BABEL_ENV === 'production'
) {
plugins.push('transform-remove-console')
}
api.cache(false)
return {
presets: [
'babel-preset-expo',
presets: ['babel-preset-expo'],
plugins: [
'@babel/plugin-proposal-optional-chaining',
[
'@babel/preset-react',
'module-resolver',
{
importSource: '@welldone-software/why-did-you-render',
runtime: 'automatic',
development:
process.env.NODE_ENV === 'development' ||
process.env.BABEL_ENV === 'development'
root: ['./'],
alias: {
'@components': './src/components',
'@i18n': './src/i18n',
'@screens': './src/screens',
'@utils': './src/utils'
}
}
]
],
plugins
].concat(
process.env.NODE_ENV === 'production' || process.env.BABEL_ENV === 'production'
? ['transform-remove-console']
: [],
['react-native-reanimated/plugin']
)
}
}

View File

@ -1,10 +1,5 @@
# 'preserve_hierarchy': true
files:
[
{
'source': '/src/i18n/en/**/*.json',
'translation': '/src/i18n/%osx_locale%/**/%original_file_name%',
'ignore': ['*.ts'],
},
]
- source: /src/i18n/en/**/*.json
translation: /src/i18n/%osx_locale%/**/%original_file_name%
ignore:
- '*.ts'

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

View File

@ -1,6 +1,3 @@
name({
'default' => "tooot"
})
keywords({
'default' => "Mastodon,tooot,social,decentralized,长毛象,社交,去中心"
})

View File

@ -36,7 +36,7 @@ private_lane :build_ios do
export_method: "app-store",
include_symbols: true,
output_directory: BUILD_DIRECTORY,
silent: false
silent: true
)
case ENVIRONMENT

View File

@ -0,0 +1 @@
../../en-US/name.txt

View File

@ -1 +0,0 @@
tooot

View File

@ -0,0 +1 @@
../../zh-Hans/name.txt

View File

@ -0,0 +1 @@
../en-US/name.txt

View File

@ -0,0 +1 @@
tooot - fediverse and Mastodon

View File

@ -1,3 +1 @@
Enjoy toooting! This version includes following improvements and fixes:
- Fixed wrongly update notification
- Fix some random crashes
Enjoy toooting! This version includes improvements and fixes.

View File

@ -1 +1 @@
Open source Mastodon client
Simple, just works

View File

@ -0,0 +1 @@
tooot - 探索联邦宇宙

View File

@ -1,3 +1 @@
toooting愉快此版本包括以下改进和修复
- 修复错误的升级通知
- 修复部分应用崩溃
tooot-ing愉快此版本包括改进和修复。

View File

@ -1 +1 @@
开源毛象客户端
简约,想你所想

View File

@ -1,8 +1,4 @@
import { registerRootComponent } from 'expo'
import App from './src/App'
import App from '@root/App'
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in the Expo client or in a native build,
// the environment is set up appropriately
registerRootComponent(App)

View File

@ -1,9 +1,20 @@
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'
install! 'cocoapods', :deterministic_uuids => false
# 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!
flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
use_frameworks! :linkage => linkage.to_sym
end
require 'json'
podfile_properties = JSON.parse(File.read('./Podfile.properties.json')) rescue {}
@ -12,13 +23,8 @@ target 'tooot' do
use_expo_modules!
config = use_native_modules!
# Flags change depending on the env values.
flags = get_default_flags()
use_react_native!(
:path => config[:reactNativePath],
:hermes_enabled => true,
:fabric_enabled => flags[:fabric_enabled],
:flipper_configuration => FlipperConfiguration.disabled,
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
@ -27,11 +33,9 @@ target 'tooot' do
post_install do |installer|
react_native_post_install(
installer,
# Set `mac_catalyst_enabled` to `true` in order to apply patches
# necessary for Mac Catalyst builds
config[:reactNativePath],
:mac_catalyst_enabled => false
)
__apply_Xcode_12_5_M1_post_install_workaround(installer)
# For share extension
installer.pods_project.targets.each do |target|
@ -39,15 +43,6 @@ target 'tooot' do
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No'
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
post_integrate do |installer|
@ -61,7 +56,6 @@ end
target 'ShareExtension' do
use_react_native!(
:hermes_enabled => true,
: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

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

View File

@ -0,0 +1,2 @@
"NSPhotoLibraryAddUsageDescription" = "Baimendu tooot-i irudiak zure kameraren rollean gordetzeko";
"NSPhotoLibraryUsageDescription" = "Baimendu tooot-i irudiak zure kameraren rollean gordetzeko";

View File

@ -0,0 +1,2 @@
"NSPhotoLibraryAddUsageDescription" = "La tooot lagre bilder på kamerarullen";
"NSPhotoLibraryUsageDescription" = "La tooot lagre bilder på kamerarullen";

View File

@ -0,0 +1,2 @@
"NSPhotoLibraryAddUsageDescription" = "Zezwól toootowi na zapisywanie zdjęć w rolce z aparatu";
"NSPhotoLibraryUsageDescription" = "Zezwól toootowi na zapisywanie zdjęć w rolce z aparatu";

View File

@ -70,14 +70,17 @@
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = tooot/SplashScreen.storyboard; sourceTree = "<group>"; };
DF8133F098604A10B0D94952 /* boop.mp3 */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = boop.mp3; path = tooot/boop.mp3; sourceTree = "<group>"; };
E613A80A28282A01003C97D6 /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = tooot/AppDelegate.mm; sourceTree = "<group>"; };
E6179D6E29B94551001930D5 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E6217B7E293C1EBF00B1755E /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E633A420281EAEAB000E540F /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
E633A427281EAEAB000E540F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; 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>"; };
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>"; };
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>"; };
E690AF692926B737002C38A8 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E69EBACA28DF282D0057EDEC /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E69EBACB28DF283A0057EDEC /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@ -85,8 +88,10 @@
E69EBACD28DF284D0057EDEC /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
E69EBACE28DF28560057EDEC /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E6A4895D293C1F740047951A /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E6B76A1E29C1147B00187ABB /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E6C8B26628F5F9FC0062CF2E /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E6D64C7A294A90840098F3AC /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E6FD3AA7299EE8A900774C18 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InfoPlist.strings; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; };
/* End PBXFileReference section */
@ -220,6 +225,7 @@
buildPhases = (
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
395686AEA3960C8699AE1CAD /* [Expo] Configure project */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
@ -300,6 +306,11 @@
nl,
ca,
uk,
nb,
be,
eu,
pl,
el,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
@ -375,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";
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 */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -382,7 +412,7 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-frameworks.sh",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
@ -401,12 +431,14 @@
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-tooot/Pods-tooot-resources.sh",
"${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";
outputPaths = (
"${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;
shellPath = /bin/sh;
@ -442,11 +474,11 @@
);
inputPaths = (
"${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";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -533,6 +565,11 @@
E6217B7E293C1EBF00B1755E /* nl */,
E6A4895D293C1F740047951A /* ca */,
E6D64C7A294A90840098F3AC /* uk */,
E6FD3AA7299EE8A900774C18 /* nb */,
E6179D6E29B94551001930D5 /* be */,
E690907B29C1133000489554 /* eu */,
E6B76A1E29C1147B00187ABB /* pl */,
E65BA25629EDEF8C008E0BBC /* el */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
@ -559,7 +596,7 @@
);
INFOPLIST_FILE = tooot/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -573,7 +610,8 @@
PRODUCT_BUNDLE_IDENTIFIER = com.xmflsct.app.tooot;
PRODUCT_NAME = tooot;
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.xmflsct.app.tooot";
SUPPORTS_MACCATALYST = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -598,7 +636,7 @@
"ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES;
INFOPLIST_FILE = tooot/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -612,7 +650,8 @@
PRODUCT_BUNDLE_IDENTIFIER = com.xmflsct.app.tooot;
PRODUCT_NAME = tooot;
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.xmflsct.app.tooot";
SUPPORTS_MACCATALYST = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SWIFT_OBJC_BRIDGING_HEADER = "tooot-Bridging-Header.h";
SWIFT_PRECOMPILE_BRIDGING_HEADER = YES;
@ -627,7 +666,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@ -664,6 +703,7 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION,
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -680,8 +720,12 @@
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"\"";
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
};
name = Debug;
};
@ -690,7 +734,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@ -722,6 +766,10 @@
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
GCC_C_LANGUAGE_STANDARD = gnu99;
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_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@ -736,9 +784,13 @@
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"\"";
MTL_ENABLE_DEBUG_INFO = NO;
ONLY_ACTIVE_ARCH = NO;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
USE_HERMES = true;
VALIDATE_PRODUCT = YES;
};
name = Release;
@ -765,8 +817,7 @@
INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -781,7 +832,8 @@
PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.xmflsct.app.tooot.ShareExtension";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match AdHoc com.xmflsct.app.tooot.ShareExtension";
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h";
@ -815,8 +867,7 @@
INFOPLIST_FILE = ShareExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = ShareExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 14.2;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -830,7 +881,8 @@
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.xmflsct.app.tooot.ShareExtension";
"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match AppStore com.xmflsct.app.tooot.ShareExtension";
SKIP_INSTALL = YES;
SUPPORTS_MACCATALYST = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "ShareExtension/ShareExtension-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-O";

View File

@ -1,9 +1,7 @@
#import <Foundation/Foundation.h>
#import <React/RCTBridgeDelegate.h>
#import <RCTAppDelegate.h>
#import <UIKit/UIKit.h>
#import <Expo/Expo.h>
@interface AppDelegate : EXAppDelegateWrapper <UIApplicationDelegate, RCTBridgeDelegate>
@interface AppDelegate : EXAppDelegateWrapper
@end

View File

@ -1,91 +1,23 @@
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTAppSetupUtils.h>
#import <React/RCTLinkingManager.h>
#import <RNShareMenu/ShareMenuManager.h>
#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil];
// NSDictionary *initProps = [self prepareInitialProps];
// UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"tooot", initProps);
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor colorNamed:@"SplashScreenBackgroundColor"];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [self.reactDelegate createRootViewController];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[super application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
/// 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` feture is enabled. Otherwise, it returns `false`.
- (BOOL)concurrentRootEnabled
{
// Switch this bool to turn on and off the concurrent root
return false;
}
- (NSDictionary *)prepareInitialProps
{
NSMutableDictionary *initProps = [NSMutableDictionary new];
#ifdef RCT_NEW_ARCH_ENABLED
initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
#endif
return initProps;
self.moduleName = @"main";
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
return [self getBundleURL];
}
- (NSURL *)getBundleURL
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
@ -94,40 +26,6 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
#endif
}
#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge delegate:self jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}
#pragma mark RCTTurboModuleManagerDelegate
- (Class)getModuleClassFromName:(const char *)name
{
return RCTCoreModulesClassProvider(name);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name initParams: (const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
#endif
// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
NSString *urlString = url.absoluteString;
@ -147,4 +45,22 @@ static NSString *const kRNConcurrentRoot = @"concurrentRoot";
restorationHandler:restorationHandler];
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
@end

View File

@ -1,90 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>tooot</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.xmflsct.app.tooot</string>
<key>CFBundleURLSchemes</key>
<array>
<string>tooot-share</string>
<string>tooot</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>2102022230</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.social-networking</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>NSMainNibFile</key>
<string>LaunchScreen</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) DOES NOT need microphone permission. Please reject this request.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to save an image to your camera roll</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your camera roll to attach photos or videos to your toot</string>
<key>UILaunchStoryboardName</key>
<string>SplashScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIRequiresFullScreen</key>
<false/>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Automatic</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>tooot</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.xmflsct.app.tooot</string>
<key>CFBundleURLSchemes</key>
<array>
<string>tooot-share</string>
<string>tooot</string>
<string>https</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>2102022230</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.social-networking</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<!-- Do not change NSAllowsArbitraryLoads to true, or you will risk app rejection! -->
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>NSMainNibFile</key>
<string>LaunchScreen</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) DOES NOT need microphone permission. Please reject this request.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to save an image to your camera roll</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your camera roll to attach photos or videos to your toot</string>
<key>UILaunchStoryboardName</key>
<string>SplashScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIRequiresFullScreen</key>
<false/>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Automatic</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<string>production</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>

View File

@ -1,3 +1,11 @@
module.exports = {
transformer: { inlineRequires: true }
}
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config')
/**
* 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",
"version": "4.7.2",
"version": "4.11.0",
"description": "tooot for Mastodon",
"author": "xmflsct <me@xmflsct.com>",
"license": "GPL-3.0-or-later",
@ -11,116 +11,111 @@
"scripts": {
"start": "react-native start",
"android": "react-native run-android",
"iphone": "react-native run-ios --simulator 'iPhone 14 Pro'",
"phone": "react-native run-ios --device",
"iphone": "react-native run-ios --simulator 'iPhone 15 Pro'",
"ipad": "react-native run-ios --simulator 'iPad Pro (11-inch) (4th generation)'",
"app:build": "bundle exec fastlane",
"clean": "react-native-clean-project",
"postinstall": "patch-package"
"clean": "react-native-clean-project"
},
"dependencies": {
"@expo/react-native-action-sheet": "^4.0.1",
"@formatjs/intl-datetimeformat": "^6.4.3",
"@formatjs/intl-getcanonicallocales": "^2.0.5",
"@formatjs/intl-locale": "^3.0.11",
"@formatjs/intl-numberformat": "^8.3.3",
"@formatjs/intl-pluralrules": "^5.1.8",
"@formatjs/intl-relativetimeformat": "^11.1.8",
"@mattermost/react-native-paste-input": "^0.5.2",
"@formatjs/intl-datetimeformat": "^6.12.2",
"@formatjs/intl-getcanonicallocales": "^2.3.0",
"@formatjs/intl-locale": "^3.4.5",
"@formatjs/intl-numberformat": "^8.10.0",
"@formatjs/intl-pluralrules": "^5.2.12",
"@formatjs/intl-relativetimeformat": "^11.2.12",
"@mattermost/react-native-paste-input": "^0.7.0",
"@neverdull-agency/expo-unlimited-secure-store": "^1.0.10",
"@react-native-async-storage/async-storage": "~1.17.11",
"@react-native-camera-roll/camera-roll": "^5.2.0",
"@react-native-clipboard/clipboard": "^1.11.1",
"@react-native-community/blur": "^4.3.0",
"@react-native-community/netinfo": "9.3.7",
"@react-native-community/segmented-control": "^2.2.2",
"@react-native-menu/menu": "^0.7.2",
"@react-navigation/bottom-tabs": "^6.5.1",
"@react-navigation/native": "^6.1.1",
"@react-navigation/native-stack": "^6.9.6",
"@react-navigation/stack": "^6.3.9",
"@reduxjs/toolkit": "^1.9.1",
"@sentry/react-native": "4.12.0",
"@sharcoux/slider": "^6.1.1",
"@tanstack/react-query": "^4.20.4",
"axios": "^1.2.1",
"@react-native-async-storage/async-storage": "~1.21.0",
"@react-native-camera-roll/camera-roll": "^7.4.0",
"@react-native-clipboard/clipboard": "^1.13.2",
"@react-native-community/blur": "^4.4.0",
"@react-native-community/netinfo": "^11.2.1",
"@react-native-firebase/app": "^18.8.0",
"@react-native-menu/menu": "^0.9.1",
"@react-native-segmented-control/segmented-control": "^2.5.0",
"@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.9",
"@react-navigation/native-stack": "^6.9.17",
"@react-navigation/stack": "^6.3.20",
"@sentry/react-native": "^5.18.0",
"@sharcoux/slider": "^7.1.1",
"@tanstack/react-query": "^4.36.1",
"axios": "^1.6.7",
"diff": "^5.1.0",
"expo": "^47.0.8",
"expo-auth-session": "^3.7.3",
"expo-av": "^13.0.2",
"expo-constants": "^14.0.2",
"expo-crypto": "^12.0.0",
"expo-file-system": "^15.1.1",
"expo-haptics": "^12.0.1",
"expo-linking": "^3.2.3",
"expo-localization": "^14.0.0",
"expo-notifications": "^0.17.0",
"expo-random": "^13.0.0",
"expo-screen-capture": "^5.0.0",
"expo-secure-store": "^12.0.0",
"expo-splash-screen": "^0.17.5",
"expo-store-review": "^6.0.0",
"expo-video-thumbnails": "^7.0.0",
"expo-web-browser": "~12.0.0",
"i18next": "^22.4.5",
"linkify-it": "^4.0.1",
"expo": "^50.0.6",
"expo-auth-session": "^5.4.0",
"expo-av": "^13.10.5",
"expo-constants": "^15.4.5",
"expo-crypto": "^12.8.0",
"expo-file-system": "^16.0.6",
"expo-haptics": "^12.8.1",
"expo-image": "^1.11.0",
"expo-linking": "^6.2.2",
"expo-localization": "^14.8.3",
"expo-notifications": "^0.27.6",
"expo-screen-capture": "^5.8.1",
"expo-screen-orientation": "^6.4.1",
"expo-secure-store": "^12.8.1",
"expo-splash-screen": "^0.26.4",
"expo-store-review": "^6.8.3",
"expo-video-thumbnails": "^7.9.0",
"expo-web-browser": "^12.8.2",
"htmlparser2": "^9.1.0",
"i18next": "^23.8.2",
"linkify-it": "^5.0.0",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^12.1.1",
"react-intl": "^6.2.5",
"react-native": "0.70.6",
"react-native-animated-spinkit": "^1.5.2",
"react-native-base64": "^0.2.1",
"react-native-blurhash": "^1.1.10",
"react-native-fast-image": "^8.6.3",
"react-native-feather": "^1.1.2",
"react-native-flash-message": "^0.3.1",
"react-native-gesture-handler": "~2.8.0",
"react-native-htmlview": "^0.16.0",
"react-native-image-picker": "^4.10.2",
"react-native-ios-context-menu": "^1.15.1",
"react-i18next": "^14.0.5",
"react-intl": "^6.6.2",
"react-native": "^0.73.4",
"react-native-flash-message": "^0.4.2",
"react-native-gesture-handler": "^2.15.0",
"react-native-image-picker": "^7.1.0",
"react-native-ios-context-menu": "^2.3.2",
"react-native-ios-utilities": "^4.3.0",
"react-native-language-detection": "^0.2.2",
"react-native-pager-view": "^6.1.2",
"react-native-reanimated": "^2.13.0",
"react-native-mmkv": "^2.11.0",
"react-native-pager-view": "^6.2.3",
"react-native-quick-base64": "^2.0.8",
"react-native-reanimated": "^3.6.2",
"react-native-reanimated-zoom": "^0.3.3",
"react-native-safe-area-context": "^4.4.1",
"react-native-screens": "^3.18.2",
"react-native-safe-area-context": "^4.9.0",
"react-native-screens": "^3.29.0",
"react-native-share-menu": "^6.0.0",
"react-native-svg": "^13.6.0",
"react-native-svg": "^14.1.0",
"react-native-swipe-list-view": "^3.2.9",
"react-native-tab-view": "^3.3.4",
"react-redux": "^8.0.5",
"redux-persist": "^6.0.0",
"react-native-tab-view": "^3.5.2",
"rn-placeholder": "^3.0.3",
"rtl-detect": "^1.0.4",
"valid-url": "^1.0.9",
"zeego": "^0.5.0"
"zeego": "^1.7.2"
},
"devDependencies": {
"@babel/core": "^7.20.5",
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@expo/config": "^7.0.3",
"@types/diff": "^5.0.2",
"@types/linkify-it": "^3.0.2",
"@types/lodash": "^4.14.191",
"@types/react": "~18.0.26",
"@types/react-dom": "~18.0.9",
"@types/react-native": "~0.70.8",
"@types/react-native-base64": "^0.2.0",
"@types/react-native-share-menu": "^5.0.2",
"@types/react-timeago": "^4.1.3",
"@types/valid-url": "^1.0.3",
"@welldone-software/why-did-you-render": "^7.0.1",
"babel-plugin-module-resolver": "^4.1.0",
"@babel/core": "^7.23.9",
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
"@babel/preset-typescript": "^7.23.3",
"@expo/config": "^8.5.4",
"@react-native/metro-config": "^0.73.5",
"@react-native/typescript-config": "^0.74.0",
"@types/diff": "^5.0.9",
"@types/linkify-it": "^3.0.5",
"@types/lodash": "^4.14.202",
"@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-transform-remove-console": "^6.9.4",
"chalk": "^4.1.2",
"dotenv": "^16.0.3",
"expo-cli": "^6.0.8",
"patch-package": "^6.5.0",
"postinstall-postinstall": "^2.1.0",
"react-native-clean-project": "^4.0.1",
"typescript": "^4.9.4"
"dotenv": "^16.4.1",
"react-native-clean-project": "^4.0.3",
"typescript": "^5.3.3"
},
"packageManager": "yarn@4.1.0",
"resolutions": {
"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",
"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

@ -1,14 +0,0 @@
diff --git a/node_modules/expo-av/ios/EXAV/EXAudioSessionManager.m b/node_modules/expo-av/ios/EXAV/EXAudioSessionManager.m
index 81dce13..8664b90 100644
--- a/node_modules/expo-av/ios/EXAV/EXAudioSessionManager.m
+++ b/node_modules/expo-av/ios/EXAV/EXAudioSessionManager.m
@@ -168,9 +168,6 @@ - (void)moduleDidBackground:(id)backgroundingModule
// compact doesn't work, that's why we need the `|| !pointer` above
// http://www.openradar.me/15396578
[_foregroundedModules compact];
-
- // Any possible failures are silent
- [self _updateSessionConfiguration];
}
- (void)moduleDidForeground:(id)module

View File

@ -1,23 +0,0 @@
diff --git a/node_modules/react-native-fast-image/RNFastImage.podspec b/node_modules/react-native-fast-image/RNFastImage.podspec
index db0fada..b23cd91 100644
--- a/node_modules/react-native-fast-image/RNFastImage.podspec
+++ b/node_modules/react-native-fast-image/RNFastImage.podspec
@@ -16,6 +16,6 @@ Pod::Spec.new do |s|
s.source_files = "ios/**/*.{h,m}"
s.dependency 'React-Core'
- s.dependency 'SDWebImage', '~> 5.11.1'
- s.dependency 'SDWebImageWebPCoder', '~> 0.8.4'
+ s.dependency 'SDWebImage', '~> 5.14.2'
+ s.dependency 'SDWebImageWebPCoder', '~> 0.9.1'
end
diff --git a/node_modules/react-native-fast-image/android/build.gradle b/node_modules/react-native-fast-image/android/build.gradle
index 5b21cd5..19d82f8 100644
--- a/node_modules/react-native-fast-image/android/build.gradle
+++ b/node_modules/react-native-fast-image/android/build.gradle
@@ -65,4 +65,5 @@ dependencies {
implementation "com.github.bumptech.glide:glide:${glideVersion}"
implementation "com.github.bumptech.glide:okhttp3-integration:${glideVersion}"
annotationProcessor "com.github.bumptech.glide:compiler:${glideVersion}"
+ implementation 'com.github.penfeizhou.android.animation:glide-plugin:2.12.0'
}

View File

@ -1,22 +0,0 @@
diff --git a/node_modules/react-native-htmlview/HTMLView.js b/node_modules/react-native-htmlview/HTMLView.js
index 43f8b7e..728112b 100644
--- a/node_modules/react-native-htmlview/HTMLView.js
+++ b/node_modules/react-native-htmlview/HTMLView.js
@@ -1,7 +1,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import htmlToElement from './htmlToElement';
-import {Linking, Platform, StyleSheet, View, ViewPropTypes} from 'react-native';
+import {Linking, Platform, StyleSheet, View} from 'react-native';
const boldStyle = {fontWeight: 'bold'};
const italicStyle = {fontStyle: 'italic'};
@@ -146,7 +146,7 @@ HtmlView.propTypes = {
renderNode: PropTypes.func,
RootComponent: PropTypes.func,
rootComponentProps: PropTypes.object,
- style: ViewPropTypes.style,
+ style: PropTypes.any,
stylesheet: PropTypes.object,
TextComponent: PropTypes.func,
textComponentProps: PropTypes.object,

19
react-native.config.js Normal file
View File

@ -0,0 +1,19 @@
module.exports = {
dependencies: {
'@react-native-firebase/app': {
platforms: {
ios: null
}
},
'@react-native-menu/menu': {
platforms: {
ios: null
}
},
'react-native-ios-context-menu': {
platforms: {
android: null
}
}
}
}

2
src/@types/app.d.ts vendored
View File

@ -3,7 +3,7 @@ declare namespace App {
| 'Following'
| 'Local'
| 'LocalPublic'
| 'Trending'
| 'Explore'
| 'Notifications'
| 'Hashtag'
| 'List'

View File

@ -1,8 +1,44 @@
import 'i18next'
import common from '../i18n/en/common.json'
import screens from '../i18n/en/screens.json'
import screenAccountSelection from '../i18n/en/screens/accountSelection.json'
import screenAnnouncements from '../i18n/en/screens/announcements.json'
import screenCompose from '../i18n/en/screens/compose.json'
import screenImageViewer from '../i18n/en/screens/imageViewer.json'
import screenTabs from '../i18n/en/screens/tabs.json'
import componentContextMenu from '../i18n/en/components/contextMenu.json'
import componentEmojis from '../i18n/en/components/emojis.json'
import componentInstance from '../i18n/en/components/instance.json'
import componentMediaSelector from '../i18n/en/components/mediaSelector.json'
import componentParse from '../i18n/en/components/parse.json'
import componentRelationship from '../i18n/en/components/relationship.json'
import componentTimeline from '../i18n/en/components/timeline.json'
declare module 'i18next' {
interface CustomTypeOptions {
defaultNS: 'common',
defaultNS: 'common'
resources: {
common: typeof common
screens: typeof screens
screenAccountSelection: typeof screenAccountSelection
screenAnnouncements: typeof screenAnnouncements
screenCompose: typeof screenCompose
screenImageViewer: typeof screenImageViewer
screenTabs: typeof screenTabs
componentContextMenu: typeof componentContextMenu
componentEmojis: typeof componentEmojis
componentInstance: typeof componentInstance
componentMediaSelector: typeof componentMediaSelector
componentParse: typeof componentParse
componentRelationship: typeof componentRelationship
componentTimeline: typeof componentTimeline
}
returnNull: false
returnEmptyString: false
}
}

View File

@ -31,6 +31,9 @@ declare namespace Mastodon {
source?: Source
suspended?: boolean
role?: Role
// Internal
_remote?: string // domain
}
type Announcement = {
@ -264,14 +267,6 @@ declare namespace Mastodon {
}
type Filter<T extends 'v1' | 'v2'> = T extends 'v2' ? Filter_V2 : Filter_V1
type Filter_V1 = {
id: string
phrase: string
context: ('home' | 'notifications' | 'public' | 'thread' | 'account')[]
expires_at?: string
irreversible: boolean
whole_word: boolean
}
type Filter_V2 = {
id: string
title: string
@ -281,6 +276,14 @@ declare namespace Mastodon {
keywords: FilterKeyword[]
statuses: FilterStatus[]
}
type Filter_V1 = {
id: string
phrase: string
context: ('home' | 'notifications' | 'public' | 'thread' | 'account')[]
expires_at?: string
irreversible: boolean
whole_word: boolean
}
type FilterKeyword = { id: string; keyword: string; whole_word: boolean }
@ -298,7 +301,48 @@ declare namespace Mastodon {
replies_policy: 'none' | 'list' | 'followed'
}
type Instance = {
type Instance<T extends 'v1' | 'v2'> = T extends 'v2' ? Instance_V2 : Instance_V1
type Instance_V2 = {
domain: string
title: string
version: string
source_url: string
description: string
usage: { users: { active_month: number } }
thumbnail: { url: string; blurhash?: string; versions?: { '@1x'?: string; '@2x'?: string } }
languages: string[]
configuration: {
urls: { streaming_api: string }
accounts: { max_featured_tags: number }
statuses: {
max_characters: number
max_media_attachments: number
characters_reserved_per_url: number
}
media_attachments: {
supported_mime_types: string[]
image_size_limit: number
image_matrix_limit: number
video_size_limit: number
video_frame_rate_limit: number
video_matrix_limit: number
}
polls: {
max_options: number
max_characters_per_option: number
min_expiration: number
max_expiration: number
}
translation: { enabled: boolean }
registrations: { enabled: boolean; approval_required: boolean; message?: string }
contact: { email: string; account: Account }
rules: Rule[]
}
// Gotosocial
account_domain?: string
}
type Instance_V1 = {
// Base
uri: string
title: string
@ -343,6 +387,9 @@ declare namespace Mastodon {
max_expiration: number
}
}
// Gotosocial
account_domain?: string
}
type Mention = {
@ -351,6 +398,9 @@ declare namespace Mastodon {
username: string
acct: string
url: string
// Internal
_remote?: string // domain
}
type Notification =
@ -402,6 +452,7 @@ declare namespace Mastodon {
'posting:default:language'?: string
'reading:expand:media'?: 'default' | 'show_all' | 'hide_all'
'reading:expand:spoilers'?: boolean
'reading:autoplay:gifs'?: boolean
}
type PushSubscription = {
@ -470,6 +521,11 @@ declare namespace Mastodon {
updated_at: string
}
type Rule = {
id: string
text: string
}
type Status = {
// Base
id: string
@ -509,6 +565,10 @@ declare namespace Mastodon {
language?: string
text?: string
filtered?: FilterResult[]
// Internal
_level?: number
_remote?: boolean
}
type StatusHistory = {

View File

@ -1,7 +1,4 @@
declare module 'gl-react-blurhash'
declare module 'htmlparser2-without-node-native'
declare module 'react-native-feather'
declare module 'react-native-htmlview'
declare module 'react-native-toast-message'
declare module 'rtl-detect'

View File

@ -1,123 +1,119 @@
import { ActionSheetProvider } from '@expo/react-native-action-sheet'
import getLanguage from '@helpers/getLanguage'
import queryClient from '@helpers/queryClient'
import i18n from '@root/i18n/i18n'
import Screens from '@root/Screens'
import audio from '@root/startup/audio'
import dev from '@root/startup/dev'
import log from '@root/startup/log'
import netInfo from '@root/startup/netInfo'
import push from '@root/startup/push'
import sentry from '@root/startup/sentry'
import timezone from '@root/startup/timezone'
import { persistor, store } from '@root/store'
import * as Sentry from '@sentry/react-native'
import { QueryClientProvider } from '@tanstack/react-query'
import AccessibilityManager from '@utils/accessibility/AccessibilityManager'
import { changeLanguage } from '@utils/slices/settingsSlice'
import { connectVerify } from '@utils/api/helpers/connect'
import getLanguage from '@utils/helpers/getLanguage'
import { queryClient } from '@utils/queryHooks'
import audio from '@utils/startup/audio'
import { dev } from '@utils/startup/dev'
import log from '@utils/startup/log'
import netInfo from '@utils/startup/netInfo'
import push from '@utils/startup/push'
import sentry from '@utils/startup/sentry'
import { GLOBAL } from '@utils/storage'
import { getGlobalStorage, setAccount, setGlobalStorage } from '@utils/storage/actions'
import { migrateFromAsyncStorage, versionStorageGlobal } from '@utils/storage/migrations/toMMKV'
import ThemeManager from '@utils/styles/ThemeManager'
import * as Localization from 'expo-localization'
import * as SplashScreen from 'expo-splash-screen'
import React, { useCallback, useEffect, useState } from 'react'
import { IntlProvider } from 'react-intl'
import { LogBox, Platform } from 'react-native'
import { Platform } from 'react-native'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { enableFreeze } from 'react-native-screens'
import { QueryClientProvider } from '@tanstack/react-query'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
import i18n from './i18n'
import Screens from './screens'
Platform.select({
android: LogBox.ignoreLogs(['Setting a timer for a long period of time'])
})
log('log', 'App', 'delay splash')
SplashScreen.preventAutoHideAsync()
dev()
sentry()
netInfo()
audio()
push()
timezone()
enableFreeze(true)
const App: React.FC = () => {
log('log', 'App', 'rendering App')
const [localCorrupt, setLocalCorrupt] = useState<string>()
const [appIsReady, setAppIsReady] = useState(false)
const [hasMigrated, setHasMigrated] = useState<boolean>(versionStorageGlobal !== undefined)
useEffect(() => {
const delaySplash = async () => {
log('log', 'App', 'delay splash')
try {
await SplashScreen.preventAutoHideAsync()
} catch (e) {
console.warn(e)
const prepare = async () => {
if (!hasMigrated) {
try {
await migrateFromAsyncStorage()
setHasMigrated(true)
} catch {}
}
const useConnect = getGlobalStorage.boolean('app.connect')
GLOBAL.connect = useConnect
log('log', 'App', `connect: ${useConnect}`)
if (useConnect) {
await connectVerify()
.then(() => log('log', 'App', 'connected'))
.catch(() => log('warn', 'App', 'connect verify failed'))
}
log('log', 'App', 'loading from MMKV')
const account = getGlobalStorage.string('account.active')
if (account) {
await setAccount(account)
} else {
log('log', 'App', 'No active account available')
const accounts = getGlobalStorage.object('accounts')
if (accounts?.length) {
log('log', 'App', `Setting active account ${accounts[accounts.length - 1]}`)
await setAccount(accounts[accounts.length - 1])
} else {
setGlobalStorage('account.active', undefined)
}
}
log('log', 'App', `locale: ${Localization.locale}`)
const language = getLanguage()
if (!language) {
if (Platform.OS !== 'ios') {
setGlobalStorage('app.language', 'en')
}
i18n.changeLanguage('en')
} else {
i18n.changeLanguage(language)
}
setAppIsReady(true)
}
delaySplash()
prepare()
}, [])
const onBeforeLift = useCallback(async () => {
let netInfoRes = undefined
try {
netInfoRes = await netInfo()
} catch {}
if (netInfoRes && netInfoRes.corrupted && netInfoRes.corrupted.length) {
setLocalCorrupt(netInfoRes.corrupted)
}
log('log', 'App', 'hide splash')
try {
const onLayoutRootView = useCallback(async () => {
if (appIsReady) {
log('log', 'App', 'hide splash')
await SplashScreen.hideAsync()
return Promise.resolve()
} catch (e) {
console.warn(e)
return Promise.reject()
}
}, [])
}, [appIsReady])
if (!appIsReady) {
return null
}
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<GestureHandlerRootView style={{ flex: 1 }} onLayout={onLayoutRootView}>
<QueryClientProvider client={queryClient}>
<Provider store={store}>
<PersistGate
persistor={persistor}
onBeforeLift={onBeforeLift}
children={bootstrapped => {
log('log', 'App', 'bootstrapped')
if (bootstrapped) {
log('log', 'App', 'loading actual app :)')
log('log', 'App', `Locale: ${Localization.locale}`)
const language = getLanguage()
if (!language) {
if (Platform.OS !== 'ios') {
store.dispatch(changeLanguage('en'))
}
i18n.changeLanguage('en')
} else {
i18n.changeLanguage(language)
}
return (
<IntlProvider locale={language}>
<SafeAreaProvider>
<ActionSheetProvider>
<AccessibilityManager>
<ThemeManager>
<Screens localCorrupt={localCorrupt} />
</ThemeManager>
</AccessibilityManager>
</ActionSheetProvider>
</SafeAreaProvider>
</IntlProvider>
)
} else {
return null
}
}}
/>
</Provider>
<SafeAreaProvider>
<ActionSheetProvider>
<AccessibilityManager>
<ThemeManager>
<Screens />
</ThemeManager>
</AccessibilityManager>
</ActionSheetProvider>
</SafeAreaProvider>
</QueryClientProvider>
</GestureHandlerRootView>
)
}
export default Sentry.wrap(App)
export default App

View File

@ -1,348 +0,0 @@
import { HeaderLeft } from '@components/Header'
import { displayMessage, Message } from '@components/Message'
import navigationRef from '@helpers/navigationRef'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import ScreenAccountSelection from '@screens/AccountSelection'
import ScreenActions from '@screens/Actions'
import ScreenAnnouncements from '@screens/Announcements'
import ScreenCompose from '@screens/Compose'
import ScreenImagesViewer from '@screens/ImagesViewer'
import ScreenTabs from '@screens/Tabs'
import * as Sentry from '@sentry/react-native'
import initQuery from '@utils/initQuery'
import { RootStackParamList } from '@utils/navigation/navigators'
import pushUseConnect from '@utils/push/useConnect'
import pushUseReceive from '@utils/push/useReceive'
import pushUseRespond from '@utils/push/useRespond'
import { updatePreviousTab } from '@utils/slices/contextsSlice'
import { checkEmojis } from '@utils/slices/instances/checkEmojis'
import { updateAccountPreferences } from '@utils/slices/instances/updateAccountPreferences'
import { updateConfiguration } from '@utils/slices/instances/updateConfiguration'
import { updateFilters } from '@utils/slices/instances/updateFilters'
import { getInstanceActive, getInstances } from '@utils/slices/instancesSlice'
import { useTheme } from '@utils/styles/ThemeManager'
import { themes } from '@utils/styles/themes'
import * as Linking from 'expo-linking'
import { addScreenshotListener } from 'expo-screen-capture'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Alert, Platform, StatusBar } from 'react-native'
import ShareMenu from 'react-native-share-menu'
import { useSelector } from 'react-redux'
import { useAppDispatch } from './store'
const Stack = createNativeStackNavigator<RootStackParamList>()
export interface Props {
localCorrupt?: string
}
const Screens: React.FC<Props> = ({ localCorrupt }) => {
const { t } = useTranslation('screens')
const dispatch = useAppDispatch()
const instanceActive = useSelector(getInstanceActive)
const { colors, theme } = useTheme()
const routeRef = useRef<{ name?: string; params?: {} }>()
// Push hooks
const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
pushUseConnect()
pushUseReceive()
pushUseRespond()
// Prevent screenshot alert
useEffect(() => {
const screenshotListener = addScreenshotListener(() =>
Alert.alert(t('screenshot.title'), t('screenshot.message'), [
{ text: t('common:buttons.confirm'), style: 'destructive' }
])
)
Platform.select({ ios: screenshotListener })
return () => screenshotListener.remove()
}, [])
// On launch display login credentials corrupt information
useEffect(() => {
const showLocalCorrect = () => {
if (localCorrupt) {
displayMessage({
message: t('localCorrupt.message'),
description: localCorrupt.length ? localCorrupt : undefined,
type: 'danger'
})
// @ts-ignore
navigationRef.navigate('Screen-Tabs', {
screen: 'Tab-Me'
})
}
}
return showLocalCorrect()
}, [localCorrupt])
// Lazily update users's preferences, for e.g. composing default visibility
useEffect(() => {
if (instanceActive !== -1) {
dispatch(updateConfiguration())
dispatch(updateFilters())
dispatch(updateAccountPreferences())
dispatch(checkEmojis())
}
}, [instanceActive])
// Callbacks
const navigationContainerOnReady = useCallback(() => {
const currentRoute = navigationRef.getCurrentRoute()
routeRef.current = {
name: currentRoute?.name,
params: currentRoute?.params ? JSON.stringify(currentRoute.params) : undefined
}
}, [])
const navigationContainerOnStateChange = useCallback(() => {
const previousRoute = routeRef.current
const currentRoute = navigationRef.getCurrentRoute()
const matchTabName = currentRoute?.name?.match(/(Tab-.*)-Root/)
if (matchTabName) {
//@ts-ignore
dispatch(updatePreviousTab(matchTabName[1]))
}
if (previousRoute?.name !== currentRoute?.name) {
Sentry.setContext('page', {
previous: previousRoute,
current: currentRoute
})
}
routeRef.current = currentRoute
}, [])
// Deep linking for compose
const [deeplinked, setDeeplinked] = useState(false)
useEffect(() => {
const getUrlAsync = async () => {
setDeeplinked(true)
const initialUrl = await Linking.parseInitialURLAsync()
if (initialUrl.path) {
const paths = initialUrl.path.split('/')
if (paths && paths.length) {
const instanceIndex = instances.findIndex(
instance => paths[0] === `@${instance.account.acct}@${instance.uri}`
)
if (instanceIndex !== -1 && instanceActive !== instanceIndex) {
initQuery({ instance: instances[instanceIndex] })
}
}
}
if (initialUrl.hostname === 'compose') {
navigationRef.navigate('Screen-Compose')
}
}
if (!deeplinked) {
getUrlAsync()
}
}, [instanceActive, instances, deeplinked])
// Share Extension
const handleShare = useCallback(
(
item?:
| {
data: { mimeType: string; data: string }[]
mimeType: undefined
}
| { data: string | string[]; mimeType: string }
) => {
if (instanceActive < 0) {
return
}
if (!item || !item.data) {
return
}
let text: string | undefined = undefined
let media: { uri: string; mime: string }[] = []
const typesImage = ['png', 'jpg', 'jpeg', 'gif']
const typesVideo = ['mp4', 'm4v', 'mov', 'webm', 'mpeg']
const filterMedia = ({ uri, mime }: { uri: string; mime: string }) => {
if (mime.startsWith('image/')) {
if (!typesImage.includes(mime.split('/')[1])) {
console.warn('Image type not supported:', mime.split('/')[1])
displayMessage({
message: t('shareError.imageNotSupported', {
type: mime.split('/')[1]
}),
type: 'danger'
})
return
}
media.push({ uri, mime })
} else if (mime.startsWith('video/')) {
if (!typesVideo.includes(mime.split('/')[1])) {
console.warn('Video type not supported:', mime.split('/')[1])
displayMessage({
message: t('shareError.videoNotSupported', {
type: mime.split('/')[1]
}),
type: 'danger'
})
return
}
media.push({ uri, mime })
} else {
if (typesImage.includes(uri.split('.').pop() || '')) {
media.push({ uri, mime: 'image/jpg' })
return
}
if (typesVideo.includes(uri.split('.').pop() || '')) {
media.push({ uri, mime: 'video/mp4' })
return
}
text = !text ? uri : text.concat(text, `\n${uri}`)
}
}
switch (Platform.OS) {
case 'ios':
if (!Array.isArray(item.data) || !item.data) {
return
}
for (const d of item.data) {
if (typeof d !== 'string') {
filterMedia({ uri: d.data, mime: d.mimeType })
}
}
break
case 'android':
if (!item.mimeType) {
return
}
if (Array.isArray(item.data)) {
for (const d of item.data) {
filterMedia({ uri: d, mime: item.mimeType })
}
} else {
filterMedia({ uri: item.data, mime: item.mimeType })
}
break
}
if (!text && !media.length) {
return
} else {
if (instances.length > 1) {
navigationRef.navigate('Screen-AccountSelection', {
share: { text, media }
})
} else {
navigationRef.navigate('Screen-Compose', {
type: 'share',
text,
media
})
}
}
},
[]
)
useEffect(() => {
ShareMenu.getInitialShare(handleShare)
}, [])
useEffect(() => {
const listener = ShareMenu.addNewShareListener(handleShare)
return () => {
listener.remove()
}
}, [])
return (
<>
<StatusBar
backgroundColor={colors.backgroundDefault}
{...(Platform.OS === 'android' && {
barStyle: theme === 'light' ? 'dark-content' : 'light-content'
})}
/>
<NavigationContainer
ref={navigationRef}
theme={themes[theme]}
onReady={navigationContainerOnReady}
onStateChange={navigationContainerOnStateChange}
>
<Stack.Navigator initialRouteName='Screen-Tabs'>
<Stack.Screen
name='Screen-Tabs'
component={ScreenTabs}
options={{ headerShown: false }}
/>
<Stack.Screen
name='Screen-Actions'
component={ScreenActions}
options={{
presentation: 'transparentModal',
animation: 'fade',
headerShown: false
}}
/>
<Stack.Screen
name='Screen-Announcements'
component={ScreenAnnouncements}
options={({ navigation }) => ({
presentation: 'transparentModal',
animation: 'fade',
headerShown: true,
headerShadowVisible: false,
headerTransparent: true,
headerStyle: { backgroundColor: 'transparent' },
headerLeft: () => <HeaderLeft content='X' onPress={() => navigation.goBack()} />,
title: t('screenAnnouncements:heading')
})}
/>
<Stack.Screen
name='Screen-Compose'
component={ScreenCompose}
options={{
headerShown: false,
presentation: 'fullScreenModal'
}}
/>
<Stack.Screen
name='Screen-ImagesViewer'
component={ScreenImagesViewer}
options={{ headerShown: false, animation: 'fade' }}
/>
<Stack.Screen
name='Screen-AccountSelection'
component={ScreenAccountSelection}
options={({ navigation }) => ({
title: t('screenAccountSelection:heading'),
headerShadowVisible: false,
presentation: 'modal',
gestureEnabled: false,
headerLeft: () => (
<HeaderLeft
type='text'
content={t('common:buttons.cancel')}
onPress={() => navigation.goBack()}
/>
)
})}
/>
</Stack.Navigator>
<Message />
</NavigationContainer>
</>
)
}
export default React.memo(Screens, () => true)

View File

@ -1,78 +0,0 @@
import axios from 'axios'
import { ctx, handleError, PagedResponse, userAgent } from './helpers'
export type Params = {
method: 'get' | 'post' | 'put' | 'delete'
domain: string
url: string
params?: {
[key: string]: string | number | boolean | string[] | number[] | boolean[]
}
headers?: { [key: string]: string }
body?: FormData | Object
}
const apiGeneral = async <T = unknown>({
method,
domain,
url,
params,
headers,
body
}: Params): Promise<PagedResponse<T>> => {
console.log(
ctx.bgGreen.bold(' API general ') +
' ' +
domain +
' ' +
method +
ctx.green(' -> ') +
`/${url}` +
(params ? ctx.green(' -> ') : ''),
params ? params : ''
)
return axios({
timeout: method === 'post' ? 1000 * 60 : 1000 * 15,
method,
baseURL: `https://${domain}/`,
url,
params,
headers: {
'Content-Type': body && body instanceof FormData ? 'multipart/form-data' : 'application/json',
Accept: '*/*',
...userAgent,
...headers
},
...(body &&
(body instanceof FormData
? (body as (FormData & { _parts: [][] }) | undefined)?._parts?.length
: Object.keys(body).length) && { data: body })
})
.then(response => {
let links: {
prev?: { id: string; isOffset: boolean }
next?: { id: string; isOffset: boolean }
} = {}
if (response.headers?.link) {
const linksParsed = response.headers.link.matchAll(
new RegExp('[?&](.*?_id|offset)=(.*?)>; *rel="(.*?)"', 'gi')
)
for (const link of linksParsed) {
switch (link[3]) {
case 'prev':
links.prev = { id: link[2], isOffset: link[1].includes('offset') }
break
case 'next':
links.next = { id: link[2], isOffset: link[1].includes('offset') }
break
}
}
}
return Promise.resolve({ body: response.data, links })
})
.catch(handleError())
}
export default apiGeneral

View File

@ -1,96 +0,0 @@
import { RootState } from '@root/store'
import axios, { AxiosRequestConfig } from 'axios'
import { ctx, handleError, PagedResponse, userAgent } from './helpers'
export type Params = {
method: 'get' | 'post' | 'put' | 'delete' | 'patch'
version?: 'v1' | 'v2'
url: string
params?: {
[key: string]: string | number | boolean | string[] | number[] | boolean[]
}
headers?: { [key: string]: string }
body?: FormData
extras?: Omit<AxiosRequestConfig, 'method' | 'url' | 'params' | 'headers' | 'data'>
}
const apiInstance = async <T = unknown>({
method,
version = 'v1',
url,
params,
headers,
body,
extras
}: Params): Promise<PagedResponse<T>> => {
const { store } = require('@root/store')
const state = store.getState() as RootState
const instanceActive = state.instances.instances.findIndex(instance => instance.active)
let domain
let token
if (instanceActive !== -1 && state.instances.instances[instanceActive]) {
domain = state.instances.instances[instanceActive].url
token = state.instances.instances[instanceActive].token
} else {
console.warn(ctx.bgRed.white.bold(' API ') + ' ' + 'No instance domain is provided')
return Promise.reject()
}
console.log(
ctx.bgGreen.bold(' API instance ') +
' ' +
domain +
' ' +
method +
ctx.green(' -> ') +
`/${url}` +
(params ? ctx.green(' -> ') : ''),
params ? params : ''
)
return axios({
timeout: method === 'post' ? 1000 * 60 : 1000 * 15,
method,
baseURL: `https://${domain}/api/${version}/`,
url,
params,
headers: {
'Content-Type': body && body instanceof FormData ? 'multipart/form-data' : 'application/json',
Accept: '*/*',
...userAgent,
...headers,
...(token && {
Authorization: `Bearer ${token}`
})
},
...((body as (FormData & { _parts: [][] }) | undefined)?._parts.length && { data: body }),
...extras
})
.then(response => {
let links: {
prev?: { id: string; isOffset: boolean }
next?: { id: string; isOffset: boolean }
} = {}
if (response.headers?.link) {
const linksParsed = response.headers.link.matchAll(
new RegExp('[?&](.*?_id|offset)=(.*?)>; *rel="(.*?)"', 'gi')
)
for (const link of linksParsed) {
switch (link[3]) {
case 'prev':
links.prev = { id: link[2], isOffset: link[1].includes('offset') }
break
case 'next':
links.next = { id: link[2], isOffset: link[1].includes('offset') }
break
}
}
}
return Promise.resolve({ body: response.data, links })
})
.catch(handleError())
}
export default apiInstance

View File

@ -11,7 +11,7 @@ import Icon from './Icon'
import CustomText from './Text'
export interface Props {
account: Mastodon.Account
account: Partial<Mastodon.Account> & Pick<Mastodon.Account, 'id' | 'acct' | 'username' | 'url'>
props?: PressableProps
}
@ -38,15 +38,16 @@ const ComponentAccount: React.FC<PropsWithChildren & Props> = ({ account, props,
<>
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
<GracefullyImage
uri={{ original: account.avatar, static: account.avatar_static }}
sources={{ default: { uri: account.avatar }, static: { uri: account.avatar_static } }}
style={{
width: StyleConstants.Avatar.S,
height: StyleConstants.Avatar.S,
borderRadius: 6,
borderRadius: StyleConstants.BorderRadius,
marginRight: StyleConstants.Spacing.S
}}
dim
/>
<View>
<View style={{ flex: 1 }}>
<CustomText numberOfLines={1}>
<ParseEmojis
content={account.display_name || account.username}
@ -68,7 +69,7 @@ const ComponentAccount: React.FC<PropsWithChildren & Props> = ({ account, props,
</View>
{props.onPress && !props.disabled ? (
<Icon
name='ChevronRight'
name='chevron-right'
size={StyleConstants.Font.Size.L}
color={colors.secondary}
style={{ marginLeft: 8 }}

View File

@ -1,38 +1,70 @@
import { useNavigation } from '@react-navigation/native'
import initQuery from '@utils/initQuery'
import { InstanceLatest } from '@utils/migrations/instances/migration'
import { ReadableAccountType, setAccount } from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import Button from './Button'
import { Pressable } from 'react-native'
import GracefullyImage from './GracefullyImage'
import haptics from './haptics'
import Icon from './Icon'
import CustomText from './Text'
interface Props {
instance: InstanceLatest
selected?: boolean
account: ReadableAccountType
additionalActions?: () => void
}
const AccountButton: React.FC<Props> = ({ instance, selected = false, additionalActions }) => {
const AccountButton: React.FC<Props> = ({ account, additionalActions }) => {
const { colors } = useTheme()
const navigation = useNavigation()
return (
<Button
type='text'
selected={selected}
<Pressable
style={{
marginBottom: StyleConstants.Spacing.M,
marginRight: StyleConstants.Spacing.M
flexDirection: 'row',
alignItems: 'center',
paddingVertical: StyleConstants.Spacing.S,
paddingHorizontal: StyleConstants.Spacing.S * 1.5,
borderColor: account.active ? colors.blue : colors.border,
borderWidth: 1,
borderRadius: 99,
marginBottom: StyleConstants.Spacing.S
}}
content={`@${instance.account.acct}@${instance.uri}${selected ? ' ✓' : ''}`}
onPress={() => {
onPress={async () => {
await setAccount(account.key)
haptics('Light')
initQuery({ instance })
navigation.goBack()
if (additionalActions) {
additionalActions()
}
}}
/>
>
<GracefullyImage
sources={{ default: { uri: account.avatar_static } }}
dimension={{
width: StyleConstants.Font.Size.L,
height: StyleConstants.Font.Size.L
}}
style={{ borderRadius: 99, overflow: 'hidden' }}
/>
<CustomText
fontStyle='M'
fontWeight={account.active ? 'Bold' : 'Normal'}
style={{
color: account.active ? colors.blue : colors.primaryDefault,
marginLeft: StyleConstants.Spacing.S
}}
children={account.acct}
/>
{account.active ? (
<Icon
name='check'
size={StyleConstants.Font.Size.L}
color={colors.blue}
style={{ marginLeft: StyleConstants.Spacing.S }}
/>
) : null}
</Pressable>
)
}

View File

@ -1,26 +1,22 @@
import Icon from '@components/Icon'
import Icon, { IconName } from '@components/Icon'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useMemo, useState } from 'react'
import React, { useState } from 'react'
import { AccessibilityProps, Pressable, StyleProp, View, ViewStyle } from 'react-native'
import { Flow } from 'react-native-animated-spinkit'
import { Loading } from './Loading'
import CustomText from './Text'
export interface Props {
export type Props = {
accessibilityLabel?: AccessibilityProps['accessibilityLabel']
accessibilityHint?: AccessibilityProps['accessibilityHint']
style?: StyleProp<ViewStyle>
type: 'icon' | 'text'
content: string
selected?: boolean
loading?: boolean
destructive?: boolean
disabled?: boolean
strokeWidth?: number
size?: 'S' | 'M' | 'L'
fontBold?: boolean
spacing?: 'XS' | 'S' | 'M' | 'L'
@ -28,7 +24,7 @@ export interface Props {
overlay?: boolean
onPress: () => void
}
} & ({ type: 'icon'; content: IconName } | { type: 'text'; content: string })
const Button: React.FC<Props> = ({
accessibilityLabel,
@ -40,7 +36,6 @@ const Button: React.FC<Props> = ({
loading = false,
destructive = false,
disabled = false,
strokeWidth,
size = 'M',
fontBold = false,
spacing = 'S',
@ -48,18 +43,16 @@ const Button: React.FC<Props> = ({
overlay = false,
onPress
}) => {
const { colors, theme } = useTheme()
const { colors } = useTheme()
const loadingSpinkit = useMemo(
() => (
const loadingSpinkit = () =>
loading ? (
<View style={{ position: 'absolute' }}>
<Flow size={StyleConstants.Font.Size[size]} color={colors.secondary} />
<Loading />
</View>
),
[theme]
)
) : null
const mainColor = useMemo(() => {
const mainColor = () => {
if (selected) {
return colors.blue
} else if (overlay) {
@ -73,29 +66,20 @@ const Button: React.FC<Props> = ({
return colors.primaryDefault
}
}
}, [theme, disabled, loading, selected])
}
const colorBackground = useMemo(() => {
if (overlay) {
return colors.backgroundOverlayInvert
} else {
return colors.backgroundDefault
}
}, [theme])
const children = useMemo(() => {
const children = () => {
switch (type) {
case 'icon':
return (
<>
<Icon
name={content}
color={mainColor}
strokeWidth={strokeWidth}
color={mainColor()}
style={{ opacity: loading ? 0 : 1 }}
size={StyleConstants.Font.Size[size] * (size === 'L' ? 1.25 : 1)}
/>
{loading ? loadingSpinkit : null}
{loadingSpinkit()}
</>
)
case 'text':
@ -103,19 +87,19 @@ const Button: React.FC<Props> = ({
<>
<CustomText
style={{
color: mainColor,
color: mainColor(),
fontSize: StyleConstants.Font.Size[size] * (size === 'L' ? 1.25 : 1),
opacity: loading ? 0 : 1
}}
fontWeight={fontBold ? 'Bold' : 'Normal'}
fontWeight={fontBold || selected ? 'Bold' : 'Normal'}
children={content}
testID='text'
/>
{loading ? loadingSpinkit : null}
{loadingSpinkit()}
</>
)
}
}, [theme, content, loading, disabled])
}
const [layoutHeight, setLayoutHeight] = useState<number | undefined>()
@ -132,12 +116,12 @@ const Button: React.FC<Props> = ({
}}
style={[
{
borderRadius: 100,
borderRadius: 99,
justifyContent: 'center',
alignItems: 'center',
borderWidth: overlay ? 0 : 1,
borderColor: mainColor,
backgroundColor: colorBackground,
borderWidth: overlay ? 0 : selected ? 1.5 : 1,
borderColor: mainColor(),
backgroundColor: overlay ? colors.backgroundOverlayInvert : colors.backgroundDefault,
paddingVertical: StyleConstants.Spacing[spacing],
paddingHorizontal: StyleConstants.Spacing[spacing] + StyleConstants.Spacing.XS,
width: round && layoutHeight ? layoutHeight : undefined
@ -149,7 +133,7 @@ const Button: React.FC<Props> = ({
})}
testID='base'
onPress={onPress}
children={children}
children={children()}
disabled={selected || disabled || loading}
/>
)

View File

@ -4,7 +4,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext } from 'react'
import { Keyboard, Pressable, View } from 'react-native'
import EmojisContext from './helpers/EmojisContext'
import EmojisContext from './Context'
const EmojisButton: React.FC = () => {
const { colors } = useTheme()
@ -35,11 +35,11 @@ const EmojisButton: React.FC = () => {
borderWidth: 2,
borderColor: colors.primaryDefault,
padding: StyleConstants.Spacing.Global.PagePadding / 2,
borderRadius: 100
borderRadius: 99
}}
>
<Icon
name={emojis.current && emojis.current.length ? 'Smile' : 'Meh'}
name={emojis.current && emojis.current.length ? 'smile' : 'meh'}
size={24}
color={
emojis.current && emojis.current.length ? colors.primaryDefault : colors.disabled

View File

@ -1,12 +1,14 @@
import { emojis } from '@components/Emojis'
import Icon from '@components/Icon'
import CustomText from '@components/Text'
import { useAppDispatch } from '@root/store'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { countInstanceEmoji } from '@utils/slices/instancesSlice'
import { connectMedia } from '@utils/api/helpers/connect'
import { StorageAccount } from '@utils/storage/account'
import { getAccountStorage, setAccountStorage } from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation'
import { useTheme } from '@utils/styles/ThemeManager'
import { Image } from 'expo-image'
import { chunk } from 'lodash'
import React, { useContext, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -18,17 +20,14 @@ import {
TextInput,
View
} from 'react-native'
import FastImage from 'react-native-fast-image'
import validUrl from 'valid-url'
import EmojisContext from './helpers/EmojisContext'
import EmojisContext from './Context'
const EmojisList = () => {
const dispatch = useAppDispatch()
const { reduceMotionEnabled } = useAccessibility()
const { t } = useTranslation()
const { t } = useTranslation(['common', 'screenCompose'])
const { emojisState, emojisDispatch } = useContext(EmojisContext)
const { colors, mode } = useTheme()
const { colors } = useTheme()
const addEmoji = (shortcode: string) => {
if (emojisState.targetIndex === -1) {
@ -69,31 +68,77 @@ const EmojisList = () => {
>
{item.map(emoji => {
const uri = reduceMotionEnabled ? emoji.static_url : emoji.url
if (validUrl.isHttpsUri(uri)) {
return (
<Pressable
key={emoji.shortcode}
onPress={() => {
addEmoji(`:${emoji.shortcode}:`)
dispatch(countInstanceEmoji(emoji))
}}
style={{ padding: StyleConstants.Spacing.S }}
>
<FastImage
accessibilityLabel={t('common:customEmoji.accessibilityLabel', {
emoji: emoji.shortcode
})}
accessibilityHint={t(
'screenCompose:content.root.footer.emojis.accessibilityHint'
)}
source={{ uri }}
style={{ width: 32, height: 32 }}
/>
</Pressable>
)
} else {
return null
}
return (
<Pressable
key={emoji.shortcode}
onPress={() => {
addEmoji(`:${emoji.shortcode}:`)
const HALF_LIFE = 60 * 60 * 24 * 7 // 1 week
const calculateScore = (
emoji: StorageAccount['emojis_frequent'][number]
): number => {
var seconds = (new Date().getTime() - emoji.lastUsed) / 1000
var score = emoji.count + 1
var order = Math.log(Math.max(score, 1)) / Math.LN10
var sign = score > 0 ? 1 : score === 0 ? 0 : -1
return (sign * order + seconds / HALF_LIFE) * 10
}
const currentEmojis = getAccountStorage.object('emojis_frequent')
const foundEmojiIndex = currentEmojis?.findIndex(
e => e.emoji.shortcode === emoji.shortcode && e.emoji.url === emoji.url
)
let newEmojisSort: StorageAccount['emojis_frequent']
if (foundEmojiIndex === -1) {
newEmojisSort = currentEmojis || []
const temp = {
emoji,
score: 0,
count: 0,
lastUsed: new Date().getTime()
}
newEmojisSort.push({
...temp,
score: calculateScore(temp),
count: temp.count + 1
})
} else {
newEmojisSort =
currentEmojis
?.map((e, i) =>
i === foundEmojiIndex
? {
...e,
score: calculateScore(e),
count: e.count + 1,
lastUsed: new Date().getTime()
}
: e
)
.sort((a, b) => b.score - a.score) || []
}
setAccountStorage([
{
key: 'emojis_frequent',
value: newEmojisSort.sort((a, b) => b.score - a.score).slice(0, 20)
}
])
}}
style={{ padding: StyleConstants.Spacing.S }}
>
<Image
accessibilityLabel={t('common:customEmoji.accessibilityLabel', {
emoji: emoji.shortcode
})}
accessibilityHint={t('screenCompose:content.root.footer.emojis.accessibilityHint')}
source={connectMedia({ uri })}
style={{ width: 32, height: 32 }}
/>
</Pressable>
)
})}
</View>
)
@ -144,7 +189,7 @@ const EmojisList = () => {
paddingRight: StyleConstants.Spacing.S
}}
>
<Icon name='Search' size={StyleConstants.Font.Size.L} color={colors.secondary} />
<Icon name='search' size={StyleConstants.Font.Size.L} color={colors.secondary} />
</View>
<TextInput
style={{
@ -158,7 +203,6 @@ const EmojisList = () => {
onChangeText={setSearch}
autoCapitalize='none'
clearButtonMode='always'
keyboardAppearance={mode}
autoCorrect={false}
spellCheck={false}
/>
@ -171,7 +215,7 @@ const EmojisList = () => {
emojisDispatch({ type: 'target', payload: -1 })
}}
>
<Icon name='ChevronDown' size={StyleConstants.Font.Size.L} color={colors.secondary} />
<Icon name='chevron-down' size={StyleConstants.Font.Size.L} color={colors.secondary} />
</Pressable>
</View>
<SectionList
@ -205,7 +249,6 @@ const EmojisList = () => {
</CustomText>
)}
renderItem={listItem}
windowSize={4}
contentContainerStyle={{
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
minHeight: 32 * 2 + StyleConstants.Spacing.M * 3

View File

@ -2,15 +2,13 @@ import EmojisButton from '@components/Emojis/Button'
import EmojisList from '@components/Emojis/List'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { useEmojisQuery } from '@utils/queryHooks/emojis'
import { getInstanceFrequentEmojis } from '@utils/slices/instancesSlice'
import { useAccountStorage } from '@utils/storage/actions'
import { chunk, forEach, groupBy, sortBy } from 'lodash'
import React, { createRef, PropsWithChildren, useEffect, useReducer, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Keyboard, KeyboardAvoidingView, View } from 'react-native'
import FastImage from 'react-native-fast-image'
import { Edge, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
import EmojisContext, { Emojis, emojisReducer, EmojisState } from './Emojis/helpers/EmojisContext'
import EmojisContext, { Emojis, emojisReducer, EmojisState } from './Context'
export type Props = {
inputProps: EmojisState['inputProps']
@ -35,9 +33,9 @@ const ComponentEmojis: React.FC<Props & PropsWithChildren> = ({
emojisDispatch({ type: 'input', payload: inputProps })
}, [inputProps])
const { t } = useTranslation()
const { t } = useTranslation(['componentEmojis'])
const { data } = useEmojisQuery({})
const frequentEmojis = useSelector(getInstanceFrequentEmojis, () => true)
const [frequentEmojis] = useAccountStorage.object('emojis_frequent')
useEffect(() => {
if (data && data.length) {
let sortedEmojis: NonNullable<Emojis['current']> = []

110
src/components/Filter.tsx Normal file
View File

@ -0,0 +1,110 @@
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { Fragment } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { Pressable, View, ViewStyle } from 'react-native'
import Icon from './Icon'
import CustomText from './Text'
export type Props = {
onPress: () => void
filter: Mastodon.Filter<'v2'>
button?: React.ReactNode
style?: ViewStyle
}
export const Filter: React.FC<Props> = ({ onPress, filter, button, style }) => {
const { t } = useTranslation(['common', 'screenTabs'])
const { colors } = useTheme()
return (
<Pressable onPress={onPress}>
<View
style={{
paddingVertical: StyleConstants.Spacing.S,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.backgroundDefault,
...style
}}
>
<View style={{ flex: 1 }}>
<CustomText
fontStyle='M'
children={filter.title}
style={{ color: colors.primaryDefault }}
numberOfLines={1}
/>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
marginVertical: StyleConstants.Spacing.XS
}}
>
{filter.expires_at && new Date() > new Date(filter.expires_at) ? (
<CustomText
fontStyle='S'
fontWeight='Bold'
children={t('screenTabs:me.preferencesFilters.expired')}
style={{ color: colors.red, marginRight: StyleConstants.Spacing.M }}
/>
) : null}
{filter.keywords?.length ? (
<CustomText
children={t('screenTabs:me.preferencesFilters.keywords', {
count: filter.keywords.length
})}
style={{ color: colors.primaryDefault }}
/>
) : null}
{filter.keywords?.length && filter.statuses?.length ? (
<CustomText
children={t('common:separator')}
style={{ color: colors.primaryDefault }}
/>
) : null}
{filter.statuses?.length ? (
<CustomText
children={t('screenTabs:me.preferencesFilters.statuses', {
count: filter.statuses.length
})}
style={{ color: colors.primaryDefault }}
/>
) : null}
</View>
<CustomText
style={{ color: colors.secondary }}
children={
<Trans
ns='screenTabs'
i18nKey='me.preferencesFilters.context'
components={[
<>
{filter.context.map((c, index) => (
<Fragment key={index}>
<CustomText
style={{ color: colors.secondary }}
children={t(`screenTabs:me.preferencesFilters.contexts.${c}`)}
/>
<CustomText children={t('common:separator')} />
</Fragment>
))}
</>
]}
/>
}
/>
</View>
{button || (
<Icon
name='chevron-right'
size={StyleConstants.Font.Size.L}
color={colors.primaryDefault}
style={{ marginLeft: 8 }}
/>
)}
</View>
</Pressable>
)
}

View File

@ -1,114 +1,95 @@
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { connectMedia } from '@utils/api/helpers/connect'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useMemo, useState } from 'react'
import {
AccessibilityProps,
Image,
Pressable,
StyleProp,
StyleSheet,
View,
ViewStyle
} from 'react-native'
import FastImage, { ImageStyle } from 'react-native-fast-image'
import { Blurhash } from 'react-native-blurhash'
// blurhas -> if blurhash, show before any loading succeed
// original -> load original
// original, remote -> if original failed, then remote
// preview, original -> first show preview, then original
// preview, original, remote -> first show preview, then original, if original failed, then remote
import { Image, ImageContentFit, ImageSource, ImageStyle } from 'expo-image'
import React, { useState } from 'react'
import { AccessibilityProps, Pressable, StyleProp, View, ViewStyle } from 'react-native'
export interface Props {
accessibilityLabel?: AccessibilityProps['accessibilityLabel']
accessibilityHint?: AccessibilityProps['accessibilityHint']
hidden?: boolean
uri: { preview?: string; original?: string; remote?: string; static?: string }
blurhash?: string
sources: {
preview?: ImageSource
default?: ImageSource
remote?: ImageSource
static?: ImageSource
blurhash?: string
}
dimension?: { width: number; height: number }
onPress?: () => void
style?: StyleProp<ViewStyle>
imageStyle?: StyleProp<ImageStyle>
// For image viewer when there is no image size available
setImageDimensions?: React.Dispatch<
React.SetStateAction<{
width: number
height: number
}>
>
imageStyle?: ImageStyle
contentFit?: ImageContentFit
dim?: boolean
withoutTransition?: boolean
enableLiveTextInteraction?: boolean
}
const GracefullyImage = ({
accessibilityLabel,
accessibilityHint,
hidden = false,
uri,
blurhash,
sources,
dimension,
onPress,
style,
imageStyle,
setImageDimensions
contentFit,
dim,
withoutTransition = false,
enableLiveTextInteraction = false
}: Props) => {
const { reduceMotionEnabled } = useAccessibility()
const { colors } = useTheme()
const [imageLoaded, setImageLoaded] = useState(false)
const { theme } = useTheme()
const source = {
uri: reduceMotionEnabled && uri.static ? uri.static : uri.original
}
const onLoad = () => {
setImageLoaded(true)
if (setImageDimensions && source.uri) {
Image.getSize(source.uri, (width, height) => setImageDimensions({ width, height }))
}
}
const blurhashView = useMemo(() => {
if (hidden || !imageLoaded) {
if (blurhash) {
return <Blurhash decodeAsync blurhash={blurhash} style={styles.placeholder} />
} else {
return <View style={[styles.placeholder, { backgroundColor: colors.shimmerDefault }]} />
}
} else {
return null
}
}, [hidden, imageLoaded])
const [currentSource, setCurrentSource] = useState<ImageSource | undefined>(
sources.default || sources.remote
)
const source: ImageSource | undefined =
reduceMotionEnabled && sources.static ? sources.static : currentSource
return (
<Pressable
{...(onPress ? { accessibilityRole: 'imagebutton' } : { accessibilityRole: 'image' })}
accessibilityLabel={accessibilityLabel}
accessibilityHint={accessibilityHint}
style={[style, dimension, { backgroundColor: colors.shimmerDefault }]}
style={[style, dimension]}
{...(onPress ? (hidden ? { disabled: true } : { onPress }) : { disabled: true })}
>
{uri.preview && !imageLoaded ? (
<FastImage
source={{ uri: uri.preview }}
style={[styles.placeholder, { backgroundColor: colors.shimmerDefault }]}
<Image
placeholderContentFit='cover'
placeholder={hidden ? sources.blurhash : sources.blurhash || connectMedia(sources.preview)}
source={hidden ? sources.blurhash : connectMedia(source)}
{...(!withoutTransition && !reduceMotionEnabled && { transition: { duration: 120 } })}
style={{ flex: 1, ...imageStyle }}
contentFit={contentFit}
onError={() => {
if (
sources.default?.uri &&
sources.default?.uri === currentSource?.uri &&
sources.remote
) {
setCurrentSource(sources.remote)
}
}}
enableLiveTextInteraction={enableLiveTextInteraction}
/>
{dim && theme !== 'light' ? (
<View
style={{
width: '100%',
height: '100%',
position: 'absolute',
backgroundColor: 'black',
opacity: theme === 'dark_lighter' ? 0.18 : 0.36
}}
/>
) : null}
<FastImage
source={{
uri: reduceMotionEnabled && uri.static ? uri.static : uri.original
}}
style={[{ flex: 1 }, imageStyle]}
onLoad={onLoad}
/>
{blurhashView}
</Pressable>
)
}
const styles = StyleSheet.create({
placeholder: {
width: '100%',
height: '100%',
position: 'absolute'
}
})
export default GracefullyImage

View File

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

View File

@ -1,67 +1,59 @@
import Icon from '@components/Icon'
import Icon, { IconName } from '@components/Icon'
import CustomText from '@components/Text'
import { useNavigation } from '@react-navigation/native'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useMemo } from 'react'
import React from 'react'
import { Pressable } from 'react-native'
export interface Props {
type?: 'icon' | 'text'
content?: string
export type Props = {
native?: boolean
background?: boolean
onPress: () => void
}
onPress?: () => void
} & ({ type?: undefined; content?: IconName } | { type: 'text'; content: string })
const HeaderLeft: React.FC<Props> = ({
type = 'icon',
type,
content,
native = true,
background = false,
onPress
}) => {
const { colors, theme } = useTheme()
const navigation = useNavigation()
const { colors } = useTheme()
const children = useMemo(() => {
const children = () => {
switch (type) {
case 'icon':
case 'text':
return (
<CustomText fontStyle='M' style={{ color: colors.primaryDefault }} children={content} />
)
default:
return (
<Icon
color={colors.primaryDefault}
name={content || 'ChevronLeft'}
name={content || 'chevron-left'}
size={StyleConstants.Spacing.M * 1.25}
/>
)
case 'text':
return (
<CustomText
fontStyle='M'
style={{ color: colors.primaryDefault }}
children={content}
/>
)
}
}, [theme])
}
return (
<Pressable
onPress={onPress}
children={children}
onPress={onPress ? onPress : () => navigation.goBack()}
children={children()}
style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: background
? colors.backgroundOverlayDefault
: undefined,
backgroundColor: background ? colors.backgroundOverlayDefault : undefined,
minHeight: 44,
minWidth: 44,
marginLeft: native
? -StyleConstants.Spacing.S
: StyleConstants.Spacing.S,
...(type === 'icon' && {
borderRadius: 100
marginLeft: native ? -StyleConstants.Spacing.S : StyleConstants.Spacing.S,
...(type === undefined && {
borderRadius: 99
}),
...(type === 'text' && {
paddingHorizontal: StyleConstants.Spacing.S

View File

@ -1,26 +1,26 @@
import Icon from '@components/Icon'
import Icon, { IconName } from '@components/Icon'
import { Loading } from '@components/Loading'
import CustomText from '@components/Text'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useMemo } from 'react'
import React from 'react'
import { AccessibilityProps, Pressable, View } from 'react-native'
import { Flow } from 'react-native-animated-spinkit'
export interface Props {
export type Props = {
accessibilityLabel?: string
accessibilityHint?: string
accessibilityState?: AccessibilityProps['accessibilityState']
type?: 'icon' | 'text'
content: string
native?: boolean
background?: boolean
loading?: boolean
disabled?: boolean
destructive?: boolean
destructiveColor?: string
onPress: () => void
}
} & ({ type?: undefined; content: IconName } | { type: 'text'; content: string })
const HeaderRight: React.FC<Props> = ({
// Accessibility - Start
@ -28,58 +28,60 @@ const HeaderRight: React.FC<Props> = ({
accessibilityHint,
accessibilityState,
// Accessibility - End
type = 'icon',
type,
content,
native = true,
background = false,
loading,
disabled,
destructive = false,
destructiveColor,
onPress
}) => {
const { colors, theme } = useTheme()
const { colors } = useTheme()
const loadingSpinkit = useMemo(
() => (
const loadingSpinkit = () =>
loading ? (
<View style={{ position: 'absolute' }}>
<Flow
size={StyleConstants.Font.Size.M * 1.25}
color={colors.secondary}
/>
<Loading />
</View>
),
[theme]
)
) : null
const children = useMemo(() => {
const children = () => {
switch (type) {
case 'icon':
case 'text':
return (
<>
<CustomText
fontStyle='M'
fontWeight={destructive ? 'Bold' : 'Normal'}
style={{
color: disabled
? colors.secondary
: destructive
? destructiveColor || colors.red
: colors.primaryDefault,
opacity: loading ? 0 : 1
}}
children={content}
/>
{loadingSpinkit()}
</>
)
default:
return (
<>
<Icon
name={content}
style={{ opacity: loading ? 0 : 1 }}
size={StyleConstants.Spacing.M * 1.25}
color={disabled ? colors.secondary : colors.primaryDefault}
color={disabled ? colors.secondary : destructive ? colors.red : colors.primaryDefault}
/>
{loading && loadingSpinkit}
</>
)
case 'text':
return (
<>
<CustomText
fontStyle='M'
style={{
color: disabled ? colors.secondary : colors.primaryDefault,
opacity: loading ? 0 : 1
}}
children={content}
/>
{loading && loadingSpinkit}
{loadingSpinkit()}
</>
)
}
}, [theme, loading, disabled])
}
return (
<Pressable
@ -88,23 +90,17 @@ const HeaderRight: React.FC<Props> = ({
accessibilityRole='button'
accessibilityState={accessibilityState}
onPress={onPress}
children={children}
children={children()}
disabled={disabled || loading}
style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: background
? colors.backgroundOverlayDefault
: undefined,
backgroundColor: background ? colors.backgroundOverlayDefault : undefined,
minHeight: 44,
minWidth: 44,
marginRight: native
? -StyleConstants.Spacing.S
: StyleConstants.Spacing.S,
...(type === 'icon' && {
borderRadius: 100
}),
marginRight: native ? -StyleConstants.Spacing.S : StyleConstants.Spacing.S,
...(type === undefined && { borderRadius: 99 }),
...(type === 'text' && {
paddingHorizontal: StyleConstants.Spacing.S
})

View File

@ -1,5 +1,5 @@
import HeaderLeft from '@components/Header/Left'
import HeaderCenter from '@components/Header/Center'
import HeaderLeft from '@components/Header/Left'
import HeaderRight from '@components/Header/Right'
export { HeaderLeft, HeaderCenter, HeaderRight }

23
src/components/Hr.tsx Normal file
View File

@ -0,0 +1,23 @@
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { View, ViewStyle } from 'react-native'
const Hr: React.FC<{ style?: ViewStyle }> = ({ style }) => {
const { colors } = useTheme()
return (
<View
style={[
{
borderTopColor: colors.border,
borderTopWidth: 1,
height: 1,
paddingVertical: StyleConstants.Spacing.S
},
style
]}
/>
)
}
export default Hr

View File

@ -1,15 +1,16 @@
import React, { createElement } from 'react'
import FeatherNames from '@expo/vector-icons/build/vendor/react-native-vector-icons/glyphmaps/Feather.json'
import Feather from '@expo/vector-icons/Feather'
import React from 'react'
import { AccessibilityProps, StyleProp, View, ViewStyle } from 'react-native'
import * as FeatherIcon from 'react-native-feather'
export type IconName = keyof typeof FeatherNames
export interface Props {
accessibilityLabel?: AccessibilityProps['accessibilityLabel']
name: string
name: IconName
size: number
color: string
fill?: string
strokeWidth?: number
style?: StyleProp<ViewStyle>
crossOut?: boolean
}
@ -19,8 +20,6 @@ const Icon: React.FC<Props> = ({
name,
size,
color,
fill,
strokeWidth = 2,
style,
crossOut = false
}) => {
@ -37,13 +36,7 @@ const Icon: React.FC<Props> = ({
}
]}
>
{createElement(FeatherIcon[name], {
width: size,
height: size,
color,
fill,
strokeWidth
})}
<Feather name={name} size={size} color={color} />
{crossOut ? (
<View
style={{
@ -51,7 +44,7 @@ const Icon: React.FC<Props> = ({
transform: [{ rotate: '45deg' }],
width: size * 1.35,
borderBottomColor: color,
borderBottomWidth: strokeWidth
borderBottomWidth: 2
}}
/>
) : null}

View File

@ -1,15 +1,17 @@
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { forwardRef, RefObject } from 'react'
import React, { ForwardedRef, forwardRef } from 'react'
import { Platform, TextInput, TextInputProps, View } from 'react-native'
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
import { EmojisState } from './Emojis/helpers/EmojisContext'
import { EmojisState } from './Emojis/Context'
import CustomText from './Text'
export type Props = {
title?: string
multiline?: boolean
} & Pick<NonNullable<EmojisState['inputProps'][0]>, 'value' | 'selection' | 'isFocused'> &
invalid?: boolean
} & Pick<NonNullable<EmojisState['inputProps'][0]>, 'value'> &
Pick<Partial<EmojisState['inputProps'][0]>, 'isFocused' | 'selection'> &
Omit<
TextInputProps,
| 'style'
@ -27,12 +29,13 @@ const ComponentInput = forwardRef(
{
title,
multiline = false,
invalid = false,
value: [value, setValue],
selection: [selection, setSelection],
selection,
isFocused,
...props
}: Props,
ref: RefObject<TextInput>
ref: ForwardedRef<TextInput>
) => {
const { colors, mode } = useTheme()
@ -43,7 +46,7 @@ const ComponentInput = forwardRef(
paddingHorizontal: withTiming(StyleConstants.Spacing.XS),
left: withTiming(StyleConstants.Spacing.S),
top: withTiming(-(StyleConstants.Font.Size.S / 2) - 2),
backgroundColor: withTiming(colors.backgroundDefault)
backgroundColor: colors.backgroundDefault
}
} else {
return {
@ -62,7 +65,7 @@ const ComponentInput = forwardRef(
borderWidth: 1,
marginVertical: StyleConstants.Spacing.S,
padding: StyleConstants.Spacing.S,
borderColor: colors.border,
borderColor: invalid ? colors.red : colors.border,
flexDirection: multiline ? 'column' : 'row',
alignItems: 'stretch'
}}
@ -78,14 +81,17 @@ const ComponentInput = forwardRef(
}}
value={value}
onChangeText={setValue}
onFocus={() => (isFocused.current = true)}
onBlur={() => (isFocused.current = false)}
onSelectionChange={({ nativeEvent }) => setSelection(nativeEvent.selection)}
{...(isFocused !== undefined && {
onFocus: () => (isFocused.current = true),
onBlur: () => (isFocused.current = false)
})}
{...(selection !== undefined && {
onSelectionChange: ({ nativeEvent }) => selection[1](nativeEvent.selection)
})}
{...(multiline && {
multiline,
numberOfLines: Platform.OS === 'android' ? 5 : undefined
})}
keyboardAppearance={mode}
textAlignVertical='top'
{...props}
/>

View File

@ -1,66 +0,0 @@
import CustomText from '@components/Text'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import { View, ViewStyle } from 'react-native'
import { PlaceholderLine } from 'rn-placeholder'
export interface Props {
style?: ViewStyle
header: string
content?: string
potentialWidth?: number
}
const InstanceInfo = React.memo(
({ style, header, content, potentialWidth }: Props) => {
const { colors } = useTheme()
return (
<View
style={[
{
flex: 1,
marginTop: StyleConstants.Spacing.M,
paddingLeft: StyleConstants.Spacing.Global.PagePadding,
paddingRight: StyleConstants.Spacing.Global.PagePadding
},
style
]}
accessible
>
<CustomText
fontStyle='S'
style={{
marginBottom: StyleConstants.Spacing.XS,
color: colors.primaryDefault
}}
fontWeight='Bold'
children={header}
/>
{content ? (
<CustomText
fontStyle='M'
style={{ color: colors.primaryDefault }}
children={content}
/>
) : (
<PlaceholderLine
width={
potentialWidth
? potentialWidth * StyleConstants.Font.Size.M
: undefined
}
height={StyleConstants.Font.LineHeight.M}
color={colors.shimmerDefault}
noMargin
style={{ borderRadius: 0 }}
/>
)}
</View>
)
},
(prev, next) => prev.content === next.content
)
export default InstanceInfo

View File

@ -1,28 +1,35 @@
import Button from '@components/Button'
import Icon from '@components/Icon'
import browserPackage from '@helpers/browserPackage'
import { useNavigation } from '@react-navigation/native'
import apiGeneral from '@utils/api/general'
import browserPackage from '@utils/helpers/browserPackage'
import { featureCheck } from '@utils/helpers/featureCheck'
import { TabMeStackNavigationProp } from '@utils/navigation/navigators'
import { queryClient } from '@utils/queryHooks'
import { redirectUri, useAppsMutation } from '@utils/queryHooks/apps'
import { useInstanceQuery } from '@utils/queryHooks/instance'
import { checkInstanceFeature, getInstances } from '@utils/slices/instancesSlice'
import { StorageAccount } from '@utils/storage/account'
import {
generateAccountKey,
getGlobalStorage,
setAccount,
setAccountStorage,
setGlobalStorage
} from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import * as AuthSession from 'expo-auth-session'
import * as WebBrowser from 'expo-web-browser'
import * as Crypto from 'expo-crypto'
import { Image } from 'expo-image'
import * as Linking from 'expo-linking'
import { debounce } from 'lodash'
import React, { RefObject, useCallback, useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { Alert, Image, KeyboardAvoidingView, Platform, TextInput, View } from 'react-native'
import { Alert, KeyboardAvoidingView, Platform, TextInput, View } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'
import { useSelector } from 'react-redux'
import { Placeholder } from 'rn-placeholder'
import validUrl from 'valid-url'
import InstanceInfo from './Info'
import { fromByteArray } from 'react-native-quick-base64'
import CustomText from '../Text'
import { useNavigation } from '@react-navigation/native'
import { TabMeStackNavigationProp } from '@utils/navigation/navigators'
import queryClient from '@helpers/queryClient'
import { useAppDispatch } from '@root/store'
import addInstance from '@utils/slices/instances/add'
import openLink from '@components/openLink'
export interface Props {
scrollViewRef?: RefObject<ScrollView>
@ -35,7 +42,7 @@ const ComponentInstance: React.FC<Props> = ({
disableHeaderImage,
goBack = false
}) => {
const { t } = useTranslation('componentInstance')
const { t } = useTranslation(['common', 'componentInstance'])
const { colors, mode } = useTheme()
const navigation = useNavigation<TabMeStackNavigationProp<'Tab-Me-Root' | 'Tab-Me-Switch'>>()
@ -44,11 +51,9 @@ const ComponentInstance: React.FC<Props> = ({
const whitelisted: boolean =
!!domain.length &&
!!errorCode &&
!!validUrl.isHttpsUri(`https://${domain}`) &&
errorCode === 401
!!(Linking.parse(`https://${domain}/`).hostname === domain) &&
(errorCode === 401 || errorCode === 500)
const dispatch = useAppDispatch()
const instances = useSelector(getInstances, () => true)
const instanceQuery = useInstanceQuery({
domain,
options: {
@ -62,8 +67,6 @@ const ComponentInstance: React.FC<Props> = ({
}
})
const deprecateAuthFollow = useSelector(checkInstanceFeature('deprecate_auth_follow'))
const appsMutation = useAppsMutation({
retry: false,
onSuccess: async (data, variables) => {
@ -75,59 +78,156 @@ const ComponentInstance: React.FC<Props> = ({
const request = new AuthSession.AuthRequest({
clientId,
clientSecret,
scopes: deprecateAuthFollow
? ['read', 'write', 'push']
: ['read', 'write', 'follow', 'push'],
redirectUri
scopes: variables.scopes,
redirectUri,
usePKCE: !['pawoo.net'].includes(domain)
})
await request.makeAuthUrlAsync(discovery)
const promptResult = await request.promptAsync(discovery)
const promptResult = await request.promptAsync(discovery, await browserPackage())
if (promptResult?.type === 'success') {
if (promptResult.type === 'success') {
const { accessToken } = await AuthSession.exchangeCodeAsync(
{
clientId,
clientSecret,
scopes: ['read', 'write', 'follow', 'push'],
scopes: variables.scopes,
redirectUri,
code: promptResult.params.code,
extraParams: { grant_type: 'authorization_code' }
extraParams: {
client_id: clientId,
client_secret: clientSecret,
grant_type: 'authorization_code',
...(request.codeVerifier && { code_verifier: request.codeVerifier })
}
},
{ tokenEndpoint: `https://${variables.domain}/oauth/token` }
)
queryClient.clear()
dispatch(
addInstance({
const {
body: { id, acct, avatar_static }
} = await apiGeneral<Mastodon.Account>({
method: 'get',
domain,
url: `api/v1/accounts/verify_credentials`,
headers: { Authorization: `Bearer ${accessToken}` }
})
const accounts = getGlobalStorage.object('accounts')
const accountKey = generateAccountKey({ domain, id })
const account = accounts?.find(account => account === accountKey)
const accountDetails: StorageAccount = {
'auth.clientId': clientId,
'auth.clientSecret': clientSecret,
'auth.token': accessToken,
'auth.domain': domain,
'auth.account.id': id,
'auth.account.acct': acct,
'auth.account.domain':
(instanceQuery.data as Mastodon.Instance_V2)?.domain ||
instanceQuery.data?.account_domain ||
((instanceQuery.data as Mastodon.Instance_V1)?.uri
? Linking.parse((instanceQuery.data as Mastodon.Instance_V1).uri).hostname
: undefined) ||
(instanceQuery.data as Mastodon.Instance_V1)?.uri ||
domain,
token: accessToken,
instance: instanceQuery.data!,
appData: { clientId, clientSecret }
})
'auth.account.avatar_static': avatar_static,
version: instanceQuery.data?.version || '0',
preferences: undefined,
notifications: {
follow: true,
follow_request: true,
favourite: true,
reblog: true,
mention: true,
poll: true,
status: true,
update: true,
'admin.sign_up': true,
'admin.report': true
},
push: {
global: false,
decode: false,
alerts: {
follow: true,
follow_request: true,
favourite: true,
reblog: true,
mention: true,
poll: true,
status: true,
update: true,
'admin.sign_up': false,
'admin.report': false
},
key: fromByteArray(Crypto.getRandomBytes(16))
},
page_local: {
showBoosts: true,
showReplies: true
},
page_me: {
followedTags: { shown: false },
lists: { shown: false },
announcements: { shown: false, unread: 0 }
},
page_account_timeline: {
excludeBoosts: true,
excludeReplies: true
},
drafts: [],
emojis_frequent: []
}
setAccountStorage(
Object.keys(accountDetails).map((key: keyof StorageAccount) => ({
key,
value: accountDetails[key]
})),
accountKey
)
if (!account) {
setGlobalStorage('accounts', (accounts || []).concat([accountKey]))
}
await setAccount(accountKey)
goBack && navigation.goBack()
}
}
})
const processUpdate = useCallback(() => {
const scopes = () =>
featureCheck('deprecate_auth_follow', instanceQuery.data?.version)
? ['read', 'write', 'push']
: ['read', 'write', 'follow', 'push']
if (domain) {
if (instances && instances.filter(instance => instance.url === domain).length) {
Alert.alert(t('update.alert.title'), t('update.alert.message'), [
{
text: t('common:buttons.cancel'),
style: 'cancel'
},
{
text: t('common:buttons.continue'),
onPress: () => appsMutation.mutate({ domain })
}
])
const accounts = getGlobalStorage.object('accounts')
if (accounts?.filter(account => account.startsWith(`${domain}/`)).length) {
Alert.alert(
t('componentInstance:update.alert.title'),
t('componentInstance:update.alert.message'),
[
{
text: t('common:buttons.cancel'),
style: 'cancel'
},
{
text: t('common:buttons.continue'),
onPress: () => appsMutation.mutate({ domain, scopes: scopes() })
}
]
)
} else {
appsMutation.mutate({ domain })
appsMutation.mutate({ domain, scopes: scopes() })
}
}
}, [domain])
}, [domain, instanceQuery.data?.version])
return (
<KeyboardAvoidingView
@ -138,16 +238,11 @@ const ComponentInstance: React.FC<Props> = ({
<View style={{ flexDirection: 'row' }}>
<Image
source={require('assets/images/welcome.png')}
style={{ resizeMode: 'contain', flex: 1, aspectRatio: 16 / 9 }}
style={{ flex: 1, aspectRatio: 16 / 9 }}
/>
</View>
) : null}
<View
style={{
marginTop: StyleConstants.Spacing.L,
marginHorizontal: StyleConstants.Spacing.Global.PagePadding
}}
>
<View style={{ marginTop: StyleConstants.Spacing.L }}>
<View
style={{
flexDirection: 'row',
@ -204,12 +299,13 @@ const ComponentInstance: React.FC<Props> = ({
text === domain &&
instanceQuery.isSuccess &&
instanceQuery.data &&
instanceQuery.data.uri
// @ts-ignore
(instanceQuery.data.domain || instanceQuery.data.uri)
) {
processUpdate()
}
}}
placeholder={' ' + t('server.textInput.placeholder')}
placeholder={' ' + t('componentInstance:server.textInput.placeholder')}
placeholderTextColor={colors.secondary}
returnKeyType='go'
keyboardAppearance={mode}
@ -222,9 +318,10 @@ const ComponentInstance: React.FC<Props> = ({
/>
<Button
type='text'
content={t('server.button')}
content={t('componentInstance:server.button')}
onPress={processUpdate}
disabled={!instanceQuery.data?.uri && !whitelisted}
// @ts-ignore
disabled={!(instanceQuery.data?.domain || instanceQuery.data?.uri) && !whitelisted}
loading={instanceQuery.isFetching || appsMutation.isLoading}
/>
</View>
@ -239,37 +336,9 @@ const ComponentInstance: React.FC<Props> = ({
paddingTop: StyleConstants.Spacing.XS
}}
>
{t('server.whitelisted')}
{t('componentInstance:server.whitelisted')}
</CustomText>
) : (
<Placeholder>
<InstanceInfo
header={t('server.information.name')}
content={instanceQuery.data?.title || undefined}
potentialWidth={2}
/>
<View style={{ flex: 1, flexDirection: 'row' }}>
<InstanceInfo
style={{ alignItems: 'flex-start' }}
header={t('server.information.accounts')}
content={instanceQuery.data?.stats?.user_count?.toString() || undefined}
potentialWidth={4}
/>
<InstanceInfo
style={{ alignItems: 'center' }}
header={t('server.information.statuses')}
content={instanceQuery.data?.stats?.status_count?.toString() || undefined}
potentialWidth={4}
/>
<InstanceInfo
style={{ alignItems: 'flex-end' }}
header={t('server.information.domains')}
content={instanceQuery.data?.stats?.domain_count?.toString() || undefined}
potentialWidth={4}
/>
</View>
</Placeholder>
)}
) : null}
<View
style={{
flexDirection: 'row',
@ -278,7 +347,7 @@ const ComponentInstance: React.FC<Props> = ({
}}
>
<Icon
name='Lock'
name='lock'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={{
@ -287,7 +356,7 @@ const ComponentInstance: React.FC<Props> = ({
}}
/>
<CustomText fontStyle='S' style={{ flex: 1, color: colors.secondary }}>
{t('server.disclaimer.base')}
{t('componentInstance:server.disclaimer.base')}
</CustomText>
</View>
<View
@ -298,7 +367,7 @@ const ComponentInstance: React.FC<Props> = ({
}}
>
<Icon
name='CheckSquare'
name='check-square'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={{
@ -312,25 +381,18 @@ const ComponentInstance: React.FC<Props> = ({
accessibilityRole='link'
>
<Trans
i18nKey='componentInstance:server.terms.base'
ns='componentInstance'
i18nKey='server.terms.base'
components={[
<CustomText
accessible
style={{ color: colors.blue }}
onPress={async () =>
WebBrowser.openBrowserAsync('https://tooot.app/privacy-policy', {
...(await browserPackage())
})
}
onPress={async () => openLink('https://tooot.app/privacy-policy')}
/>,
<CustomText
accessible
style={{ color: colors.blue }}
onPress={async () =>
WebBrowser.openBrowserAsync('https://tooot.app/terms-of-service', {
...(await browserPackage())
})
}
onPress={async () => openLink('https://tooot.app/terms-of-service')}
/>
]}
/>

View File

@ -0,0 +1,12 @@
import { useTheme } from '@utils/styles/ThemeManager'
import { ActivityIndicator, ViewProps } from 'react-native'
export type Props = {
size?: 'small' | 'large'
} & ViewProps
export const Loading: React.FC<Props> = ({ size = 'small', ...rest }) => {
const { colors } = useTheme()
return <ActivityIndicator size={size} color={colors.secondary} {...rest} />
}

View File

@ -1,17 +1,19 @@
import React from 'react'
import { View } from 'react-native'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react'
import { View, ViewStyle } from 'react-native'
export interface Props {
style?: ViewStyle
children: React.ReactNode
}
const MenuContainer: React.FC<Props> = ({ children }) => {
const MenuContainer: React.FC<Props> = ({ style, children }) => {
return (
<View
style={{
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
marginBottom: StyleConstants.Spacing.Global.PagePadding
marginBottom: StyleConstants.Spacing.Global.PagePadding,
...style
}}
>
{children}

View File

@ -1,8 +1,8 @@
import React from 'react'
import { View } from 'react-native'
import CustomText from '@components/Text'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import CustomText from '@components/Text'
import React from 'react'
import { View } from 'react-native'
export interface Props {
heading: string

View File

@ -1,16 +1,16 @@
import Icon from '@components/Icon'
import Icon, { IconName } from '@components/Icon'
import { Loading } from '@components/Loading'
import CustomText from '@components/Text'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { ColorDefinitions } from '@utils/styles/themes'
import React, { useMemo } from 'react'
import React from 'react'
import { View } from 'react-native'
import { Flow } from 'react-native-animated-spinkit'
import { State, Switch, TapGestureHandler } from 'react-native-gesture-handler'
export interface Props {
iconFront?: any
iconFront?: IconName
iconFrontColor?: ColorDefinitions
title: string
@ -22,7 +22,7 @@ export interface Props {
switchDisabled?: boolean
switchOnValueChange?: () => void
iconBack?: 'ChevronRight' | 'ExternalLink' | 'Check'
iconBack?: 'chevron-right' | 'chevron-down' | 'external-link' | 'check'
iconBackColor?: ColorDefinitions
loading?: boolean
@ -44,18 +44,9 @@ const MenuRow: React.FC<Props> = ({
loading = false,
onPress
}) => {
const { colors, theme } = useTheme()
const { colors } = useTheme()
const { screenReaderEnabled } = useAccessibility()
const loadingSpinkit = useMemo(
() => (
<View style={{ position: 'absolute' }}>
<Flow size={StyleConstants.Font.Size.M * 1.25} color={colors.secondary} />
</View>
),
[theme]
)
return (
<View
style={{ minHeight: 50 }}
@ -75,14 +66,7 @@ const MenuRow: React.FC<Props> = ({
}}
>
<View style={{ flex: 1 }}>
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: StyleConstants.Spacing.S
}}
>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}>
<View
style={{
flexShrink: 3,
@ -105,7 +89,7 @@ const MenuRow: React.FC<Props> = ({
width: 8,
height: 8,
backgroundColor: colors.red,
borderRadius: 8,
borderRadius: StyleConstants.BorderRadius,
marginRight: StyleConstants.Spacing.S
}}
/>
@ -157,7 +141,11 @@ const MenuRow: React.FC<Props> = ({
style={{ marginLeft: 8, opacity: loading ? 0 : 1 }}
/>
) : null}
{loading && loadingSpinkit}
{loading ? (
<View style={{ position: 'absolute' }}>
<Loading />
</View>
) : null}
</View>
) : null}
</View>

View File

@ -4,7 +4,6 @@ import { useTheme } from '@utils/styles/ThemeManager'
import React, { RefObject } from 'react'
import { AccessibilityInfo } from 'react-native'
import FlashMessage, { MessageType, showMessage } from 'react-native-flash-message'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import haptics from './haptics'
const displayMessage = ({
@ -53,16 +52,15 @@ const displayMessage = ({
const Message = React.forwardRef<FlashMessage>((_, ref) => {
const { colors, theme } = useTheme()
const insets = useSafeAreaInsets()
enum iconMapping {
success = 'CheckCircle',
danger = 'XCircle',
warning = 'AlertCircle',
none = '',
default = '',
info = '',
auto = ''
success = 'check-circle',
danger = 'x-circle',
warning = 'alert-circle',
none = 'x',
default = 'x',
info = 'x',
auto = 'x'
}
enum colorMapping {
success = 'blue',
@ -96,8 +94,7 @@ const Message = React.forwardRef<FlashMessage>((_, ref) => {
shadowOffset: { width: 0, height: 0 },
shadowOpacity: theme === 'light' ? 0.16 : 0.24,
shadowRadius: 4,
paddingRight: StyleConstants.Spacing.M * 2,
marginTop: ref ? undefined : insets.top
paddingRight: StyleConstants.Spacing.M * 2
}}
titleStyle={{
color: colors.primaryDefault,
@ -109,7 +106,7 @@ const Message = React.forwardRef<FlashMessage>((_, ref) => {
...StyleConstants.FontStyle.S
}}
// @ts-ignore
textProps={{ numberOfLines: 2 }}
textProps={{ numberOfLines: 3 }}
/>
)
})

View File

@ -0,0 +1,29 @@
import { useHeaderHeight } from '@react-navigation/elements'
import { StyleConstants } from '@utils/styles/constants'
import { ForwardedRef, forwardRef, PropsWithChildren } from 'react'
import { KeyboardAvoidingView, Platform, ScrollView } from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
export const ModalScrollView = forwardRef(
({ children }: PropsWithChildren, ref: ForwardedRef<ScrollView>) => {
const headerHeight = useHeaderHeight()
return (
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
keyboardVerticalOffset={headerHeight}
>
<SafeAreaView style={{ flex: 1 }} edges={['bottom']}>
<ScrollView
ref={ref}
keyboardShouldPersistTaps='always'
contentContainerStyle={{ padding: StyleConstants.Spacing.Global.PagePadding }}
>
{children}
</ScrollView>
</SafeAreaView>
</KeyboardAvoidingView>
)
}
)

View File

@ -1,4 +0,0 @@
import ParseEmojis from './Parse/Emojis'
import ParseHTML from './Parse/HTML'
export { ParseEmojis, ParseHTML }

View File

@ -1,99 +1,102 @@
import CustomText from '@components/Text'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { getSettingsFontsize } from '@utils/slices/settingsSlice'
import { connectMedia } from '@utils/api/helpers/connect'
import { useGlobalStorage } from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager'
import { Image } from 'expo-image'
import React from 'react'
import { Platform, TextStyle } from 'react-native'
import FastImage from 'react-native-fast-image'
import { useSelector } from 'react-redux'
import validUrl from 'valid-url'
import { ColorValue, Platform, TextStyle } from 'react-native'
const regexEmoji = new RegExp(/(:[A-Za-z0-9_]+:)/)
export interface Props {
content: string
content?: string
emojis?: Mastodon.Emoji[]
size?: 'S' | 'M' | 'L'
color?: ColorValue
adaptiveSize?: boolean
fontBold?: boolean
style?: TextStyle
}
const ParseEmojis = React.memo(
({ content, emojis, size = 'M', adaptiveSize = false, fontBold = false, style }: Props) => {
const { reduceMotionEnabled } = useAccessibility()
const ParseEmojis: React.FC<Props> = ({
content,
emojis,
size = 'M',
color,
adaptiveSize = false,
fontBold = false,
style
}) => {
if (!content) return null
const adaptiveFontsize = useSelector(getSettingsFontsize)
const adaptedFontsize = adaptiveScale(
StyleConstants.Font.Size[size],
adaptiveSize ? adaptiveFontsize : 0
)
const adaptedLineheight = adaptiveScale(
StyleConstants.Font.LineHeight[size],
adaptiveSize ? adaptiveFontsize : 0
)
const { reduceMotionEnabled } = useAccessibility()
const { colors, theme } = useTheme()
const [adaptiveFontsize] = useGlobalStorage.number('app.font_size')
const adaptedFontsize = adaptiveScale(
StyleConstants.Font.Size[size],
adaptiveSize ? adaptiveFontsize : 0
)
const adaptedLineheight = adaptiveScale(
StyleConstants.Font.LineHeight[size],
adaptiveSize ? adaptiveFontsize : 0
)
return (
<CustomText
style={[
{
color: colors.primaryDefault,
fontSize: adaptedFontsize,
lineHeight: adaptedLineheight
},
style
]}
fontWeight={fontBold ? 'Bold' : undefined}
>
{emojis ? (
content
.split(regexEmoji)
.filter(f => f)
.map((str, i) => {
if (str.match(regexEmoji)) {
const emojiShortcode = str.split(regexEmoji)[1]
const emojiIndex = emojis.findIndex(emoji => {
return emojiShortcode === `:${emoji.shortcode}:`
})
if (emojiIndex === -1) {
return <CustomText key={emojiShortcode + i}>{emojiShortcode}</CustomText>
} else {
const uri = reduceMotionEnabled
? emojis[emojiIndex].static_url
: emojis[emojiIndex].url
if (validUrl.isHttpsUri(uri)) {
return (
<CustomText key={emojiShortcode + i}>
{i === 0 ? ' ' : undefined}
<FastImage
source={{ uri }}
style={{
width: adaptedFontsize,
height: adaptedFontsize,
transform: [{ translateY: Platform.OS === 'ios' ? -1 : 2 }]
}}
/>
</CustomText>
)
} else {
return null
}
}
const { colors } = useTheme()
return (
<CustomText
style={[
{
color: color || colors.primaryDefault,
fontSize: adaptedFontsize,
lineHeight: adaptedLineheight
},
style
]}
fontWeight={fontBold ? 'Bold' : undefined}
>
{emojis ? (
content
.split(regexEmoji)
.filter(f => f)
.map((str, i) => {
if (str.match(regexEmoji)) {
const emojiShortcode = str.split(regexEmoji)[1]
const emojiIndex = emojis.findIndex(emoji => {
return emojiShortcode === `:${emoji.shortcode}:`
})
if (emojiIndex === -1) {
return <CustomText key={emojiShortcode + i}>{emojiShortcode}</CustomText>
} else {
return <CustomText key={i}>{str}</CustomText>
const uri = reduceMotionEnabled
? emojis[emojiIndex].static_url
: emojis[emojiIndex].url
return (
<CustomText key={emojiShortcode + i}>
{i === 0 ? ' ' : undefined}
<Image
source={connectMedia({ uri })}
style={{
width: adaptedFontsize,
height: adaptedFontsize,
transform: [{ translateY: Platform.OS === 'ios' ? -1 : 2 }]
}}
/>
</CustomText>
)
}
})
) : (
<CustomText>{content}</CustomText>
)}
</CustomText>
)
},
(prev, next) => prev.content === next.content
)
} else {
return <CustomText key={i}>{str}</CustomText>
}
})
) : (
<CustomText>{content}</CustomText>
)}
</CustomText>
)
}
export default ParseEmojis

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