Compare commits

..

867 Commits

Author SHA1 Message Date
LucasGGamerM
b70b6a633a refactor(SavedPostsTimelineFragment.java): add getFilterContext and getWebUri methods back 2025-05-19 10:12:34 -03:00
LucasGGamerM
3976902ef6 refactor(AccountTimelineFragment.java): add getFilterContext and getWebUri methods back 2025-05-19 10:12:02 -03:00
LucasGGamerM
858f9eea7b refactor(HomeFragment.java): make it compile for now by removing loaded check 2025-05-19 10:08:45 -03:00
LucasGGamerM
37503953a8 refactor(LocalTimelineFragment.java): add LocalTimelineFragment back 2025-05-19 10:07:42 -03:00
LucasGGamerM
fe0c093600 refactor(FederatedTimelineFragment.java): add FederatedTimelineFragment back 2025-05-19 10:05:52 -03:00
LucasGGamerM
85a701de1c refactor(BubbleTimelineFragment.java): add BubbleTimelineFragment back 2025-05-19 10:05:26 -03:00
LucasGGamerM
ef7f4d98e0 refactor(AccountNotificationsListFragment.java): add getWebUri method back 2025-05-19 10:04:31 -03:00
LucasGGamerM
548e61c0c7 refactor(HashtagTimelineFragment.java): make onFabClick public 2025-05-19 10:03:42 -03:00
LucasGGamerM
63b9d45698 refactor(AnnouncementsFragment.java): add back non working Announcements fragment 2025-05-19 10:01:34 -03:00
LucasGGamerM
63972f53d1 refactor(BookMarkedStatusListFragment.java): add back the bookmarked timeline 2025-05-19 10:00:35 -03:00
LucasGGamerM
d980d35d6f refactor(CustomLocalTimelineFragment.java): add back the custom local timelines fragment 2025-05-19 09:55:39 -03:00
LucasGGamerM
e037633ca9 refactor(FavoriteStatusListFragment.java): add back the favorited timeline 2025-05-19 09:54:17 -03:00
LucasGGamerM
1c76c5d514 refactor(EditTimelinesFragment.java): add the edit timelines fragment back 2025-05-19 09:53:42 -03:00
LucasGGamerM
e5b3cbf259 refactor(HasElevationOnScrollListener.java): add interface back 2025-05-19 09:52:38 -03:00
LucasGGamerM
f30bc56d81 refactor(PinnedPostsListFragment.java): add getWebUri and getFilterContext methods back 2025-05-19 09:35:51 -03:00
LucasGGamerM
1c6788d5d3 refactor(CreateListAddMembersFragment.java): add getWebUri method back 2025-05-18 09:49:06 -03:00
LucasGGamerM
1aa25c40ea refactor(FeaturedHashtagsListFragment.java): open hashtags through UiUtils method 2025-05-18 09:46:11 -03:00
LucasGGamerM
85cef5d81b refactor(HashtagTimelineFragment.java): add getFilterContext and getWebUri methods back 2025-05-18 09:44:39 -03:00
LucasGGamerM
f222698cc0 refactor(HashtagFeaturedTimelineFragment.java): add getFilterContext and getWebUri methods back 2025-05-18 09:43:38 -03:00
LucasGGamerM
33f917e9c7 refactor(FeaturedHashtagsListFragment): add getWebUri method back 2025-05-18 09:41:49 -03:00
LucasGGamerM
d6ec0de931 refactor(NotificationsListFragment.java): add getWebUri method back 2025-05-18 09:40:39 -03:00
LucasGGamerM
597c4b568f refactor(ProfileFeaturedFragment.java): add getWebUri method back 2025-05-18 09:39:27 -03:00
LucasGGamerM
ccd09636b8 refactor(ThreadFragment.java): add getFilterContext and getWebUri methods back 2025-05-18 09:37:07 -03:00
LucasGGamerM
b0942b6b0c refactor(StatusListFragment.java): add abstract getFilterContext method back 2025-05-18 09:33:46 -03:00
LucasGGamerM
724be185f0 refactor(ListMembers.java): add getWebUri method back 2025-05-18 09:23:42 -03:00
LucasGGamerM
123f5aa22e refactor(HomeTabFragment.java): bring back the working HomeTabFragment implementation 2025-05-18 09:23:12 -03:00
LucasGGamerM
789087376f refactor(ListTimeline.java): add Moshidon fields back
We don't use this implementation, but we keep it so the app still compiles
2025-05-18 09:20:27 -03:00
LucasGGamerM
f6cbfa0bd4 refactor(ListTimelineCustomFragment.java): add our custom list timeline implementation 2025-05-18 09:06:28 -03:00
LucasGGamerM
6795e37bb1 refactor(PinnableStatusListFragment.java): add PinnableStatusListFragment.java back 2025-05-18 09:05:31 -03:00
LucasGGamerM
52c28afcf2 refactor(ComposeFragment.java): add LOCAL visibility switch case 2025-05-18 09:04:50 -03:00
LucasGGamerM
1beeb02ac3 refactor(BaseNotificationsListFragment.java): swap to custom reblog or reply line status display item 2025-05-18 09:03:22 -03:00
LucasGGamerM
33953ef6ba refactor(SearchFragment.java): add getWebUri method back
It's empty for now, but it will be populated sometime
2025-05-11 10:52:31 -03:00
LucasGGamerM
b561935172 refactor(DiscoverPostsFragment.java): add getWebUri and getFilterContext methods back 2025-05-11 10:25:41 -03:00
LucasGGamerM
d18bfa5432 refactor(DiscoverAccountsFragment.java): add getWebUri method back 2025-05-11 10:23:50 -03:00
LucasGGamerM
95f9f76dbd refactor(StatusDisplayItem.java): add inset and status fields back 2025-04-29 14:20:19 -03:00
LucasGGamerM
7c767f8967 refactor(StatusDisplayItem.java): add Moshidon specific flags back 2025-04-29 14:19:34 -03:00
LucasGGamerM
b9b98bcfd9 refactor(StatusDisplayItem.java): add DUMMY and EMOJI_REACTIONS enums 2025-04-29 14:18:30 -03:00
LucasGGamerM
1ca4a3f549 refactor(StatusDisplayItem.java): swap the upstream ReblogOrReplyLine references to the custom Moshidon one 2025-04-29 14:17:30 -03:00
LucasGGamerM
f409228893 refactor(StatusDisplayItem.java): add filterContext parameter to the build method 2025-04-29 14:16:21 -03:00
LucasGGamerM
f9ebfce016 refactor(FooterStatusDisplayItem.java): add LOCAL only privacy case in reblog button state switch 2025-04-29 14:06:05 -03:00
LucasGGamerM
22ab3419bb refactor(OnboardingFollowSuggestionsFragment.java): add Moshidon specific methods back 2025-04-29 14:05:08 -03:00
LucasGGamerM
af1e0fc541 refactor(ReportReasonChoiceFragment.java): add Moshidon specific fields back 2025-04-29 14:04:32 -03:00
LucasGGamerM
7e36c665f2 refactor(ReportAddPostsChoiceFragment.java): add Moshidon specific methods back 2025-04-29 14:03:21 -03:00
LucasGGamerM
b5fff6ab89 refactor(EmojiReactionsStatusDisplayItem.java): readd the EmojiReactionsStatusDisplayItem
No emoji reactions support yet, as upstream appkit changed how recycler views work and therefore this will not work as is.
2025-04-29 14:02:49 -03:00
LucasGGamerM
b9c5769a0a refactor(DummyStatusDisplayItem.java): readd DummyStatusDisplayItem.java 2025-04-29 14:00:48 -03:00
LucasGGamerM
648b4b9bc6 refactor(ReblogOrReplyLineCustomStatusDisplayItem.java): readd the Moshidon custom reply line status display item 2025-04-29 14:00:17 -03:00
LucasGGamerM
935f5508eb refactor(AccountSwitcherSheet.java): add the account chooser stuff back 2025-04-27 09:54:35 -03:00
LucasGGamerM
61d72e2456 refactor(DiscoverInfoBannerHelper.java): update timeline definitions 2025-04-27 09:52:36 -03:00
LucasGGamerM
b93747c16f refactor(CustomEmojiSpan.java): make drawable field protected, because AvatarSpan uses it 2025-04-27 09:49:24 -03:00
LucasGGamerM
a86e90ced6 refactor(UiUtils.java): add Moshidon specific methods back 2025-04-25 08:08:02 -03:00
LucasGGamerM
1630eb0e88 refactor(AvatarSpan.java): add back the AvatarSpan class 2025-04-25 08:06:23 -03:00
LucasGGamerM
0616145b2a refactor(ListEditor.java): add back the working ListEditor version 2025-04-25 08:05:35 -03:00
LucasGGamerM
3572712e7c refactor(display_item_reblog_or_reply_line_custom.java): add Moshidon's custom layout back 2025-04-25 08:04:33 -03:00
LucasGGamerM
241591b4bf refactor(PhotoViewer.java): add LOCAL visibility parameter to PhotoViewer boost state switch 2025-04-25 08:03:41 -03:00
LucasGGamerM
506c118094 refactor(CustomLocalTimeline.java): add back the CustomLocalTimeline model 2025-04-25 07:59:17 -03:00
LucasGGamerM
18600ed5fa refactor(ScheduledStatus.java): add the scheduled status model back 2025-04-25 07:56:16 -03:00
LucasGGamerM
93a301cd21 refactor(TimelineDefinition.java): change previous list timeline class name to ListTimelineCustomFragment 2025-04-25 07:51:18 -03:00
LucasGGamerM
c1384d6abc refactor(Account.java): add akkoma fields and Moshidon methods back 2025-04-25 07:49:05 -03:00
LucasGGamerM
0a2fe4cc0d refactor(Instance.java): add the thumbnail parameter back 2025-04-19 11:37:47 -03:00
LucasGGamerM
4a923d506d refactor(EmojiReaction.java): add back the EmojiReaction model
No emoji reactions support just yet
2025-04-19 11:33:11 -03:00
LucasGGamerM
2740d5d267 refactor(Poll.java): add back Option constructors 2025-04-19 11:28:30 -03:00
LucasGGamerM
21cd4c3c36 refactor(Emoji.java): add back Moshidon specific constructors and getUrl method 2025-04-19 11:27:40 -03:00
LucasGGamerM
d07a1c80e7 refactor(Status.java): add back Moshidon specfic fields and ofFake method 2025-04-19 11:26:39 -03:00
LucasGGamerM
f87617b7ef refactor(HtmlParser.java): add back the text method 2025-04-19 11:22:26 -03:00
LucasGGamerM
40bfff6819 refactor(MastodonApiController.java): revert to working version with no deviations from upstream 2025-04-19 11:16:35 -03:00
LucasGGamerM
b12fbfa355 refactor(StatusTextEncoder.java): add back this utility
Why do I still do this aaaaaaaaaaaa
2025-04-16 13:01:56 -03:00
LucasGGamerM
f9187c27c8 refactor(display_item_warning.xml): add back the resource file for the warning status display item 2025-04-16 12:59:46 -03:00
LucasGGamerM
ba711bbe18 refactor(AkkomaTranslateStatus.java): add the AkkomaTranslateStatus api method 2025-04-16 12:52:42 -03:00
LucasGGamerM
e541a99751 refactor(AkkomaTranslation.java): add the AkkomaTranslation model back 2025-04-16 12:51:59 -03:00
LucasGGamerM
043cfb9171 refactor(ReblogDeletedEvent.java): add back ReblogDeletedEvent.java 2025-04-16 12:47:41 -03:00
LucasGGamerM
e8db6c5f39 refactor(Instance.java): add back the translation support fields on Instance.java 2025-04-16 12:43:15 -03:00
LucasGGamerM
0b39b6547b refactor(MastodonAPIController.java): add the gsonWithoutDeserializer back
I wonder why this is necessary :D
2025-04-16 12:32:58 -03:00
LucasGGamerM
2ac2f8c4e6 refactor(StatusCountersUpdatedEvent.java): add back the pinned parameter 2025-04-16 12:25:22 -03:00
LucasGGamerM
3362ee328a refactor(LegacyFilter.java): add the title parameter back 2025-04-16 12:22:07 -03:00
LucasGGamerM
0cb26e9bfb refactor(StatusMuteChangedEvent.java): add back StatusMuteChangedEvent.java 2025-04-16 12:08:38 -03:00
LucasGGamerM
85b003e768 refactor(ListTimeline.java): add the ListTimeline model back 2025-04-16 12:05:11 -03:00
LucasGGamerM
2ccd21adde refactor(Searchable.java): add back the Searchable interface 2025-04-16 12:02:04 -03:00
LucasGGamerM
2aa010c127 refactor: add back bg_button_m3_tonal_circle_selector.xml drawable 2025-04-16 12:00:16 -03:00
LucasGGamerM
8f2cfb44ab refactor(EmojiReactionsRecyclerView.java): add back the EmojiReactionsRecyclerView view 2025-04-16 11:53:04 -03:00
LucasGGamerM
70e15856a8 refactor(ListEditor.java): add back the popup ListEditor view 2025-04-16 11:52:12 -03:00
LucasGGamerM
4d6b3d3ffe refactor(HeaderSubtitleLinearLayout.java): add back the firstFraction layout parameter 2025-04-16 11:48:14 -03:00
LucasGGamerM
f6655c0af1 refactor(TextInputFrameLayout.java): add back the TextInputFrameLayout.java file 2025-04-16 11:47:11 -03:00
LucasGGamerM
43ff783014 refactor(TextDrawable.java): add back TextDrawable.java 2025-04-13 12:59:14 -03:00
LucasGGamerM
2df7aade48 refactor(StatusPrivacy.java): add back the isReblogPermitted method 2025-04-13 12:56:38 -03:00
LucasGGamerM
4d4543351f refactor(StatusPrivacy.java): add local only status privacy (for akkoma) 2025-04-13 12:56:04 -03:00
LucasGGamerM
8444e54060 refactor(ContentType.java): add the ContentType class back. Full implementation is still missing 2025-04-13 12:44:45 -03:00
LucasGGamerM
af19a03f96 refactor(display_item_emoji_reactions.xml): add the amoji reactions display item layout resource file back 2025-04-11 09:13:26 -03:00
LucasGGamerM
f39eccbf1d refactor(compose_fab.xml): add the compose_fab.xml layout resource file back 2025-04-11 09:12:47 -03:00
LucasGGamerM
4d4d06de84 refactor(edit_timeline.xml): add back the edit timeline layout resource 2025-04-11 09:07:36 -03:00
LucasGGamerM
eecd1996cc refactor(home_toolbar.xml): add the home toolbar layout resource file back 2025-04-11 09:06:19 -03:00
LucasGGamerM
796a04682e refactor(item_emoji_reaction.xml): add the emoji reactions item layout resource back 2025-04-11 09:04:03 -03:00
LucasGGamerM
3b9ef836da refactor(item_external_share_heading.xml): add the item_external_share_heading.xml layout resource file back 2025-04-11 09:01:44 -03:00
LucasGGamerM
b1d3760269 refactor(item_text.xml): add the item_text.xml layout resource file back 2025-04-11 08:59:37 -03:00
LucasGGamerM
07fe58ddae refactor(list_timeline_editor.xml): add the list timeline editor layout resource back 2025-04-11 08:58:47 -03:00
LucasGGamerM
cd959ed563 refactor(custom_local_timelines.xml): add the custom local timelines menu resource file back 2025-04-11 08:56:31 -03:00
LucasGGamerM
38f42f8a23 refactor(list.xml): add the list menu resource file back 2025-04-11 08:55:42 -03:00
LucasGGamerM
8d7a7349d4 refactor(list_reply_policies.xml): add back the list reply policies menu resource 2025-04-11 08:54:36 -03:00
LucasGGamerM
a0305dbad4 refactor(home_overflow.xml): add the overflow home menu resource back 2025-04-11 08:53:55 -03:00
LucasGGamerM
82309b9cb4 refactor(home.xml): add the main home menu resource back 2025-04-11 08:51:42 -03:00
LucasGGamerM
802b7d6399 refactor(ids.xml): menu item ids relevant to the timelines editor 2025-04-11 08:46:02 -03:00
LucasGGamerM
4b3de40507 refactor(palettes.xml): add back the palettes.xml file 2025-04-11 08:22:41 -03:00
LucasGGamerM
df4f051e22 refactor(styles.xml): add Moshidon specific style resources 2025-04-11 08:20:37 -03:00
LucasGGamerM
59f1b7f5ef refactor(colors.xml): comment out primary_700, shortcut_icon_background, shortcut_icon_foreground values
They are on colors_custom.xml, so we removed them here just for the sake of the happiness of our java compiler
2025-04-11 08:16:34 -03:00
LucasGGamerM
8089d2757b refactor(colors_custom.xml): readd our themes' color data in separate resource file. No custom colors yet though 2025-04-11 08:13:29 -03:00
LucasGGamerM
949998129f refactor(attrs.xml): readd Moshidon specific attributes 2025-04-11 08:06:50 -03:00
LucasGGamerM
0cd1e97760 refactor(Announcement.java): add the Announcement model back, no full announcements fragment yet 2025-04-09 10:51:12 -03:00
LucasGGamerM
76a6e5ec3b refactor(TimelineDefinition.java): add TimelineDefinition so that we can have our HomeTabFragment all nice and dandy 2025-04-09 10:50:01 -03:00
LucasGGamerM
45a2e12db7 feat(StatusEmojiReactionsListFragment): add back the emoji reactions list fragment
This is still not useful, because the emoji status display item is broken for now because of a couple of deprecations
2025-04-07 11:12:50 -03:00
LucasGGamerM
03f89e6c26 refactor(StatusRelatedAccountListFragment.java): add getWebUri method back 2025-04-07 11:11:24 -03:00
LucasGGamerM
08b0ef8560 refactor(StatusFavoritesListFragment.java): add getWebUri method back 2025-04-07 11:10:45 -03:00
LucasGGamerM
46630d183b refactor(FollowingListFragment.java): add getWebUri method back 2025-04-07 11:10:04 -03:00
LucasGGamerM
f86154914a refactor(FollowerListFragment.java): add getWebUri method back 2025-04-07 11:09:36 -03:00
LucasGGamerM
56651cf7b6 refactor(FamiliarFollowerListFragment.java): add getWebUri method back 2025-04-07 11:08:57 -03:00
LucasGGamerM
86b200fc46 refactor(AccountSearchFragment.java): add getWebUri method back 2025-04-07 11:07:18 -03:00
LucasGGamerM
8d11c5b66a refactor(AccountRelatedAccountListFragment.java): add getWebUri method back 2025-04-07 11:03:21 -03:00
LucasGGamerM
9ad5fb191d refactor(BaseAccountListFragment.java): add ProvidesAssistContent dependency
This should be part 1, because there we still have to implement this method on the other fragments that depend on this
2025-04-07 11:01:51 -03:00
LucasGGamerM
5248ae9e08 refactor(BaseAccountListFragment.java): add getAccountID method back 2025-04-07 11:00:21 -03:00
LucasGGamerM
d44a3813fd refactor(bg_button_m3_tonal_selector): add bg_button_m3_tonal_selector drawable back 2025-04-03 11:54:25 -03:00
LucasGGamerM
0109293d7d refactor(HasAccountID): add HasAccountID.java back 2025-04-03 11:52:57 -03:00
LucasGGamerM
5e619c06b1 refactor(HasFab): add HasFab.java back 2025-04-03 11:52:20 -03:00
LucasGGamerM
5873e887f6 refactor(isOnTop): add IsOnTop.java back 2025-04-03 11:51:23 -03:00
LucasGGamerM
d048b0edbc feat(google-pixel-launcher-url): add ProvidesAssistContent.java 2025-04-03 11:49:57 -03:00
LucasGGamerM
8273685914 refactor(Instance.java): add back pleroma, akkoma, and pixelfed specific fields 2025-04-03 11:40:17 -03:00
LucasGGamerM
fe70b9876c refactor(AccountSession.java): add getInstanceUri and getInstance methods back 2025-04-03 11:33:08 -03:00
LucasGGamerM
deaa94ae4c refactor(AccountLocalPreferences.java): add session parameter to constructor 2025-04-03 11:32:08 -03:00
LucasGGamerM
eedcb2f62b refactor(hashtags): add HashtagUpdatedEvent 2025-04-01 11:45:30 -03:00
LucasGGamerM
3c31060970 refactor(lists): add ListUpdatedCreatedEvent 2025-04-01 11:43:23 -03:00
LucasGGamerM
6f32136616 refactor(GetPublicTimeline.java): add reply visibility parameter 2025-04-01 11:42:31 -03:00
LucasGGamerM
ff201014b3 refactor(bubble-timeline): add GetBubbleTimeline api method 2025-04-01 11:41:11 -03:00
LucasGGamerM
16629de7d2 refactor(scheduled-statuses): add scheduled status created/deleted events 2025-04-01 11:40:23 -03:00
LucasGGamerM
43ff91f8e5 refactor(scheduled-statuses): add GetScheduledStatuses api method 2025-04-01 11:39:39 -03:00
LucasGGamerM
dd616d91f7 refactor(lists): add "reply_visibility" parameter to GetListTimeline method 2025-04-01 11:38:04 -03:00
LucasGGamerM
68e5de8599 refactor(lists): add GetList api method 2025-04-01 11:36:43 -03:00
LucasGGamerM
97ba55dcab refactor(emoji-reactions): add EmojiReactionsUpdatedEvent 2025-04-01 11:36:12 -03:00
LucasGGamerM
c1cb32e7d2 refactor(emoji-reactions): add api methods 2025-04-01 11:35:38 -03:00
LucasGGamerM
215f8eb2e5 build: add diff_match_patch dependency 2025-04-01 11:34:56 -03:00
LucasGGamerM
f45abcb4e5 build: add nachos dependency 2025-04-01 11:34:12 -03:00
LucasGGamerM
6b5448a864 refactor: add back all announcements api methods 2025-02-21 12:06:52 -03:00
LucasGGamerM
f88bcf9354 refactor: add more missing drawables 2025-02-15 14:34:23 -03:00
LucasGGamerM
b26b6a8339 refactor: readd drawables/animators used by our styles.xml 2025-01-19 16:00:20 -03:00
LucasGGamerM
cb368ad17c refactor: put all Moshidon local and global settings into place 2025-01-10 15:22:58 -03:00
LucasGGamerM
23eb36a45d chore: readd the stock mastodon android drawables back to git 2024-12-14 17:19:56 -03:00
LucasGGamerM
5a8b15c157 build: remove microsoft fluent icons dependency
We have imported all the icons manually on 1e12ba2bfc
2024-12-10 12:04:27 -03:00
LucasGGamerM
1e12ba2bfc chore: add all fluent icons xmls 2024-12-10 11:56:38 -03:00
LucasGGamerM
ceb65b991f feat(readd-home-tab-fragment): part 1: add HomeTabFragment references and rename HomeTimelineFragment references.
No major changes have been done yet. This will be a one hell of a pain in the arse :D
2024-12-05 10:24:35 -03:00
LucasGGamerM
547a2caa9c fix(profile-notes): save note on refresh 2024-11-25 14:46:42 -03:00
LucasGGamerM
8fc4ba093a feat: add private notes
This is still missing the icon on the top bar, which we will add when we come back to adding the profile menus
2024-11-25 14:34:56 -03:00
LucasGGamerM
9d20b0e72b feat: use CustomWelcomeFragment when adding second accounts 2024-11-25 14:04:19 -03:00
LucasGGamerM
572a4ab8e6 build: change applicationId, version code and version name to Moshidon values 2024-11-25 11:36:50 -03:00
LucasGGamerM
824516d60b build: comment out all appcenter things in build.gradle 2024-11-25 11:29:06 -03:00
LucasGGamerM
514f6b6cd5 feat: readd search on long press search icon 2024-11-24 11:43:35 -03:00
LucasGGamerM
deff0ed118 feat: readd search on double click search icon 2024-11-23 11:11:22 -03:00
LucasGGamerM
62ae5a63e5 feat: add profile_own_custom.xml menu file 2024-11-20 10:59:42 -03:00
LucasGGamerM
c2904ec808 fix: readd fluent icons to header_welcome_custom.xml 2024-11-20 10:48:30 -03:00
LucasGGamerM
36b92c80fb fix: readd fluent icons to item_instance_custom.xml 2024-11-20 10:48:15 -03:00
LucasGGamerM
78224674a0 build: add fluent icons as a dependency 2024-11-20 10:07:09 -03:00
LucasGGamerM
42dc06f6cc chore: readd the CustomWelcomeFragment 2024-11-19 16:00:46 -03:00
LucasGGamerM
33b65ba1f2 chore: readd the english strings from Megalodon/Moshidon 2024-11-19 15:15:06 -03:00
LucasGGamerM
c34797c974 chore: readd strings from megalodon/moshidon 2024-11-18 07:22:31 -03:00
LucasGGamerM
5f9ebf304f docs: change readme 2024-11-18 07:12:25 -03:00
LucasGGamerM
8417878c80 build: remove appcenter dependencies 2024-11-18 07:01:40 -03:00
Gregory K
eae55c6e71 Merge pull request #932 from likeazir/emoji-performance
Limit autocompleted emojis to 50
2024-11-18 00:52:57 +03:00
Gregory K
85fd88337e Merge pull request #933 from likeazir/fix-sql-substr-index
fix sql strings are indexed at 1
2024-11-18 00:52:42 +03:00
likeazir
af8c071b4a fix sql strings are indexed at 1 2024-11-17 22:15:41 +01:00
Jonas
1638a936d9 Merge branch 'mastodon:master' into emoji-performance 2024-11-17 22:08:52 +01:00
Grishka
ad2f4791c2 Merge branch 'l10n_master' 2024-11-16 15:14:33 +03:00
Grishka
c468e9958f Crash fixes 2024-11-16 15:13:48 +03:00
Grishka
a217167667 Increase robustness of instance data loading 2024-11-16 15:04:46 +03:00
Eugen Rochko
af1ae2fa01 New translations strings.xml (Japanese) 2024-11-15 19:08:14 +01:00
Eugen Rochko
5be9ae7cce New translations strings.xml (Japanese) 2024-11-15 17:52:47 +01:00
Eugen Rochko
548abe8d90 New translations strings.xml (Vietnamese) 2024-11-15 07:29:19 +01:00
Grishka
357041b995 Prepare for release 2024-11-15 01:15:59 +03:00
Grishka
6754f004f2 Merge branch 'l10n_master' 2024-11-15 01:13:48 +03:00
Eugen Rochko
3487b0b70d New translations strings.xml (Italian) 2024-11-14 00:11:39 +01:00
likeazir
d0e49a710d limit autocomplete to 50 emojis 2024-11-13 21:18:47 +01:00
Gregory K
f91b887586 Merge pull request #921 from owo-uwu-nyaa/master
Make sure cursor stays under 1MB size limit
2024-11-13 20:30:23 +03:00
Jonas
62cd754f3a Merge branch 'mastodon:master' into master 2024-11-13 18:08:48 +01:00
likeazir
be82274bee consistent naming 2024-11-13 17:52:01 +01:00
likeazir
6779b5cc43 single queries for domains to prevent running into the cursor limit 2024-11-13 17:49:30 +01:00
likeazir
86e369201a remove extra query to get emoji row length 2024-11-13 17:32:46 +01:00
Eugen Rochko
6b2fd26961 New translations strings.xml (Lithuanian) 2024-11-13 11:33:32 +01:00
Eugen Rochko
423718b4f2 New translations strings.xml (Lithuanian) 2024-11-13 09:33:41 +01:00
Eugen Rochko
f6ed37f80f New translations strings.xml (Chinese Traditional) 2024-11-13 01:46:55 +01:00
Eugen Rochko
71a986b280 New translations strings.xml (Swedish) 2024-11-12 22:45:23 +01:00
Eugen Rochko
12375609e3 New translations strings.xml (Interlingua) 2024-11-12 20:42:20 +01:00
Eugen Rochko
02659407f8 New translations strings.xml (Kabyle) 2024-11-12 20:42:18 +01:00
Eugen Rochko
a4f0e577f5 New translations strings.xml (Scottish Gaelic) 2024-11-12 20:42:16 +01:00
Eugen Rochko
9bc4d81321 New translations strings.xml (Filipino) 2024-11-12 20:42:13 +01:00
Eugen Rochko
72dd2e1b65 New translations strings.xml (Welsh) 2024-11-12 20:42:12 +01:00
Eugen Rochko
58e74708f5 New translations strings.xml (Thai) 2024-11-12 20:42:09 +01:00
Eugen Rochko
77855154d3 New translations strings.xml (Persian) 2024-11-12 20:42:07 +01:00
Eugen Rochko
d77fcff253 New translations strings.xml (Indonesian) 2024-11-12 20:42:05 +01:00
Eugen Rochko
5358c889e4 New translations strings.xml (Portuguese, Brazilian) 2024-11-12 20:42:04 +01:00
Eugen Rochko
bcbf3412a7 New translations strings.xml (Galician) 2024-11-12 20:42:03 +01:00
Eugen Rochko
17a481e797 New translations strings.xml (Vietnamese) 2024-11-12 20:42:01 +01:00
Eugen Rochko
dce8d38237 New translations strings.xml (Chinese Traditional) 2024-11-12 20:42:00 +01:00
Eugen Rochko
1cf250765b New translations strings.xml (Chinese Simplified) 2024-11-12 20:41:59 +01:00
Eugen Rochko
d136060b6f New translations strings.xml (Ukrainian) 2024-11-12 20:41:57 +01:00
Eugen Rochko
6dd7d779dd New translations strings.xml (Turkish) 2024-11-12 20:41:56 +01:00
Eugen Rochko
aca2843991 New translations strings.xml (Swedish) 2024-11-12 20:41:55 +01:00
Eugen Rochko
04f46cbecc New translations strings.xml (Slovenian) 2024-11-12 20:41:54 +01:00
Eugen Rochko
9fbca3a7d6 New translations strings.xml (Russian) 2024-11-12 20:41:52 +01:00
Eugen Rochko
a6a71ce8b6 New translations strings.xml (Portuguese) 2024-11-12 20:41:50 +01:00
Eugen Rochko
31d8a85e35 New translations strings.xml (Polish) 2024-11-12 20:41:49 +01:00
Eugen Rochko
63a3069041 New translations strings.xml (Norwegian) 2024-11-12 20:41:48 +01:00
Eugen Rochko
96750bb80a New translations strings.xml (Dutch) 2024-11-12 20:41:47 +01:00
Eugen Rochko
e53df3d1b1 New translations strings.xml (Lithuanian) 2024-11-12 20:41:45 +01:00
Eugen Rochko
8a5a681b86 New translations strings.xml (Korean) 2024-11-12 20:41:44 +01:00
Eugen Rochko
06d2df4773 New translations strings.xml (Japanese) 2024-11-12 20:41:42 +01:00
Eugen Rochko
723bdb9fed New translations strings.xml (Italian) 2024-11-12 20:41:41 +01:00
Eugen Rochko
774601bc6c New translations strings.xml (Armenian) 2024-11-12 20:41:40 +01:00
Eugen Rochko
909fbcb54a New translations strings.xml (Hungarian) 2024-11-12 20:41:38 +01:00
Eugen Rochko
1dd422918a New translations strings.xml (Finnish) 2024-11-12 20:41:36 +01:00
Eugen Rochko
7c433ccea9 New translations strings.xml (Greek) 2024-11-12 20:41:34 +01:00
Eugen Rochko
56602a88e1 New translations strings.xml (German) 2024-11-12 20:41:33 +01:00
Eugen Rochko
dd838689c5 New translations strings.xml (Danish) 2024-11-12 20:41:32 +01:00
Eugen Rochko
8b54f2960b New translations strings.xml (Czech) 2024-11-12 20:41:31 +01:00
Eugen Rochko
782f828073 New translations strings.xml (Catalan) 2024-11-12 20:41:29 +01:00
Eugen Rochko
32c0a3985e New translations strings.xml (Belarusian) 2024-11-12 20:41:28 +01:00
Eugen Rochko
6bfee114db New translations strings.xml (Arabic) 2024-11-12 20:41:27 +01:00
Eugen Rochko
fb0bbe3b11 New translations strings.xml (Spanish) 2024-11-12 20:41:25 +01:00
Eugen Rochko
64d0adc3ff New translations strings.xml (French) 2024-11-12 20:41:23 +01:00
Eugen Rochko
942c9998ba New translations strings.xml (Frisian) 2024-11-12 20:41:21 +01:00
Eugen Rochko
864d6fb7a5 New translations strings.xml (Icelandic) 2024-11-12 20:41:19 +01:00
Eugen Rochko
9286de4580 New translations strings.xml (Basque) 2024-11-12 20:41:18 +01:00
Grishka
6e4590caf2 Fix #820, probably 2024-11-12 22:40:48 +03:00
Grishka
ea1216b352 Show the direction on gaps + bug fix 2024-11-12 22:12:05 +03:00
Eugen Rochko
c2cd886844 New translations strings.xml (Swedish) 2024-11-12 19:38:17 +01:00
Eugen Rochko
83e5a041a3 New translations strings.xml (Swedish) 2024-11-12 18:38:19 +01:00
Eugen Rochko
a10bbab6d2 New translations strings.xml (Interlingua) 2024-11-12 16:55:50 +01:00
Eugen Rochko
ed36774f16 New translations strings.xml (Urdu (India)) 2024-11-12 16:55:49 +01:00
Eugen Rochko
6663c1c2be New translations strings.xml (Kabyle) 2024-11-12 16:55:48 +01:00
Eugen Rochko
6d448fbb5c New translations strings.xml (Igbo) 2024-11-12 16:55:47 +01:00
Eugen Rochko
25a49971bb New translations strings.xml (Occitan) 2024-11-12 16:55:45 +01:00
Eugen Rochko
3300660321 New translations strings.xml (Scottish Gaelic) 2024-11-12 16:55:44 +01:00
Eugen Rochko
39cf4b6678 New translations strings.xml (Sinhala) 2024-11-12 16:55:43 +01:00
Eugen Rochko
0edf1a5653 New translations strings.xml (Bosnian) 2024-11-12 16:55:42 +01:00
Eugen Rochko
52473e69cc New translations strings.xml (Filipino) 2024-11-12 16:55:41 +01:00
Eugen Rochko
0981ef5d68 New translations strings.xml (Welsh) 2024-11-12 16:55:40 +01:00
Eugen Rochko
4ed29cde81 New translations strings.xml (Burmese) 2024-11-12 16:55:39 +01:00
Eugen Rochko
25c05dcc51 New translations strings.xml (Hindi) 2024-11-12 16:55:38 +01:00
Eugen Rochko
afab3a04ca New translations strings.xml (Croatian) 2024-11-12 16:55:36 +01:00
Eugen Rochko
8a6e00d2bb New translations strings.xml (Thai) 2024-11-12 16:55:35 +01:00
Eugen Rochko
678dc12595 New translations strings.xml (Bengali) 2024-11-12 16:55:34 +01:00
Eugen Rochko
7390550cd2 New translations strings.xml (Persian) 2024-11-12 16:55:32 +01:00
Eugen Rochko
e4d193eb6c New translations strings.xml (Indonesian) 2024-11-12 16:55:31 +01:00
Eugen Rochko
ebe19a4393 New translations strings.xml (Portuguese, Brazilian) 2024-11-12 16:55:30 +01:00
Eugen Rochko
fe0ae9a425 New translations strings.xml (Galician) 2024-11-12 16:55:29 +01:00
Eugen Rochko
9b82c8b066 New translations strings.xml (Vietnamese) 2024-11-12 16:55:27 +01:00
Eugen Rochko
0a1df389e7 New translations strings.xml (Chinese Traditional) 2024-11-12 16:55:26 +01:00
Eugen Rochko
1735a3ba9a New translations strings.xml (Chinese Simplified) 2024-11-12 16:55:25 +01:00
Eugen Rochko
7ba6d37ebf New translations strings.xml (Ukrainian) 2024-11-12 16:55:23 +01:00
Eugen Rochko
7d59ca27fc New translations strings.xml (Turkish) 2024-11-12 16:55:22 +01:00
Eugen Rochko
323ede05a9 New translations strings.xml (Swedish) 2024-11-12 16:55:21 +01:00
Eugen Rochko
2c2dcf3c28 New translations strings.xml (Slovenian) 2024-11-12 16:55:20 +01:00
Eugen Rochko
1f5b1ba3f9 New translations strings.xml (Slovak) 2024-11-12 16:55:18 +01:00
Eugen Rochko
ec81a53e88 New translations strings.xml (Russian) 2024-11-12 16:55:17 +01:00
Eugen Rochko
324ef1cce9 New translations strings.xml (Portuguese) 2024-11-12 16:55:16 +01:00
Eugen Rochko
f4cae9c51f New translations strings.xml (Polish) 2024-11-12 16:55:15 +01:00
Eugen Rochko
0e92626755 New translations strings.xml (Norwegian) 2024-11-12 16:55:13 +01:00
Eugen Rochko
0d6658ca72 New translations strings.xml (Dutch) 2024-11-12 16:55:12 +01:00
Eugen Rochko
ac812704f0 New translations strings.xml (Lithuanian) 2024-11-12 16:55:10 +01:00
Eugen Rochko
5dbcf68aca New translations strings.xml (Korean) 2024-11-12 16:55:09 +01:00
Eugen Rochko
6a2395a3c5 New translations strings.xml (Georgian) 2024-11-12 16:55:07 +01:00
Eugen Rochko
be020bd742 New translations strings.xml (Japanese) 2024-11-12 16:55:06 +01:00
Eugen Rochko
1e19fbe4f9 New translations strings.xml (Italian) 2024-11-12 16:55:05 +01:00
Eugen Rochko
b18fecf9d8 New translations strings.xml (Armenian) 2024-11-12 16:55:04 +01:00
Eugen Rochko
3cde5435c0 New translations strings.xml (Hungarian) 2024-11-12 16:55:02 +01:00
Eugen Rochko
b988a455e3 New translations strings.xml (Hebrew) 2024-11-12 16:55:01 +01:00
Eugen Rochko
8c3ebaf784 New translations strings.xml (Irish) 2024-11-12 16:55:00 +01:00
Eugen Rochko
a381d338ef New translations strings.xml (Finnish) 2024-11-12 16:54:59 +01:00
Eugen Rochko
c04733411a New translations strings.xml (Greek) 2024-11-12 16:54:57 +01:00
Eugen Rochko
9218cb728e New translations strings.xml (German) 2024-11-12 16:54:56 +01:00
Eugen Rochko
e00bb3f6e9 New translations strings.xml (Danish) 2024-11-12 16:54:54 +01:00
Eugen Rochko
6727ec5119 New translations strings.xml (Czech) 2024-11-12 16:54:53 +01:00
Eugen Rochko
4d7a6d9476 New translations strings.xml (Catalan) 2024-11-12 16:54:52 +01:00
Eugen Rochko
858cc34298 New translations strings.xml (Belarusian) 2024-11-12 16:54:51 +01:00
Eugen Rochko
5ac37290df New translations strings.xml (Arabic) 2024-11-12 16:54:50 +01:00
Eugen Rochko
efd9690d10 New translations strings.xml (Spanish) 2024-11-12 16:54:48 +01:00
Eugen Rochko
2985c5490b New translations strings.xml (French) 2024-11-12 16:54:47 +01:00
Eugen Rochko
f70101279d New translations strings.xml (Romanian) 2024-11-12 16:54:46 +01:00
Eugen Rochko
9fe52e7853 New translations strings.xml (Frisian) 2024-11-12 16:54:44 +01:00
Eugen Rochko
f8059b2810 New translations strings.xml (Icelandic) 2024-11-12 16:54:43 +01:00
Eugen Rochko
372add3cf8 New translations strings.xml (Basque) 2024-11-12 16:54:42 +01:00
Grishka
134bd13d60 Show followers/following number when blocking a server (AND-233) 2024-11-12 18:49:05 +03:00
Eugen Rochko
a53959d707 New translations strings.xml (Lithuanian) 2024-11-12 12:36:31 +01:00
Eugen Rochko
2a6d87a513 New translations strings.xml (Italian) 2024-11-12 12:36:30 +01:00
Eugen Rochko
b2a9ce998d New translations strings.xml (Italian) 2024-11-12 10:31:58 +01:00
Eugen Rochko
7c63943814 New translations strings.xml (Italian) 2024-11-12 01:19:56 +01:00
likeazir
4b5f84d781 remove stray newline 2024-11-11 17:18:15 +01:00
likeazir
5c75ada632 rudimentary pagination fix to keep emoji size under 1MB cursor limit 2024-11-11 17:05:12 +01:00
Eugen Rochko
964b84ec79 New translations full_description.txt (Icelandic) 2024-11-11 13:02:37 +01:00
Eugen Rochko
55db777906 New translations strings.xml (Chinese Traditional) 2024-11-11 10:19:36 +01:00
Eugen Rochko
16b8724045 New translations strings.xml (Icelandic) 2024-11-10 15:35:26 +01:00
Eugen Rochko
87c425b89c New translations strings.xml (Spanish) 2024-11-10 01:29:53 +01:00
Grishka
20ed47032e Add filters to search (AND-106) 2024-11-08 20:13:31 +03:00
Grishka
91d65b4e27 Fix search view state restoration & animation 2024-11-08 19:53:30 +03:00
Eugen Rochko
5a0ed9b7c1 New translations strings.xml (Italian) 2024-11-07 20:36:16 +01:00
Eugen Rochko
b62963c4f3 New translations strings.xml (Italian) 2024-11-07 19:31:50 +01:00
Eugen Rochko
f0a00f6919 New translations strings.xml (Swedish) 2024-11-07 13:25:16 +01:00
Grishka
8ea049c956 Fix refresh 2024-11-07 14:04:40 +03:00
Grishka
ff5e281db7 Minor fixes in profiles 2024-11-07 14:02:13 +03:00
Eugen Rochko
65189753eb New translations strings.xml (Interlingua) 2024-11-07 11:53:47 +01:00
Eugen Rochko
0944682bef New translations strings.xml (Kabyle) 2024-11-07 11:53:46 +01:00
Eugen Rochko
aa41b9bef2 New translations strings.xml (Scottish Gaelic) 2024-11-07 11:53:43 +01:00
Eugen Rochko
668286215b New translations strings.xml (Welsh) 2024-11-07 11:53:40 +01:00
Eugen Rochko
bf1d709892 New translations strings.xml (Thai) 2024-11-07 11:53:36 +01:00
Eugen Rochko
4ae49029d0 New translations strings.xml (Persian) 2024-11-07 11:53:35 +01:00
Eugen Rochko
90a1860a1c New translations strings.xml (Indonesian) 2024-11-07 11:53:27 +01:00
Eugen Rochko
f3e8a0c6c9 New translations strings.xml (Portuguese, Brazilian) 2024-11-07 11:53:25 +01:00
Eugen Rochko
661a54f006 New translations strings.xml (Vietnamese) 2024-11-07 11:53:23 +01:00
Eugen Rochko
9f9e3f8eba New translations strings.xml (Chinese Traditional) 2024-11-07 11:53:22 +01:00
Eugen Rochko
6a9fb76677 New translations strings.xml (Chinese Simplified) 2024-11-07 11:53:21 +01:00
Eugen Rochko
c81288e694 New translations strings.xml (Ukrainian) 2024-11-07 11:53:20 +01:00
Eugen Rochko
594f044068 New translations strings.xml (Turkish) 2024-11-07 11:53:19 +01:00
Eugen Rochko
147485633c New translations strings.xml (Swedish) 2024-11-07 11:53:17 +01:00
Eugen Rochko
4498a0f226 New translations strings.xml (Slovenian) 2024-11-07 11:53:16 +01:00
Eugen Rochko
1df56fc320 New translations strings.xml (Russian) 2024-11-07 11:53:14 +01:00
Eugen Rochko
1e2f47dd2a New translations strings.xml (Polish) 2024-11-07 11:53:12 +01:00
Eugen Rochko
26f5fbf3b8 New translations strings.xml (Norwegian) 2024-11-07 11:53:11 +01:00
Eugen Rochko
ecd2cecfa6 New translations strings.xml (Dutch) 2024-11-07 11:53:10 +01:00
Eugen Rochko
f6ecd25e1d New translations strings.xml (Lithuanian) 2024-11-07 11:53:09 +01:00
Eugen Rochko
1ac088f5a3 New translations strings.xml (Japanese) 2024-11-07 11:53:06 +01:00
Eugen Rochko
0030a06cd3 New translations strings.xml (Italian) 2024-11-07 11:53:05 +01:00
Eugen Rochko
6b7d1b0981 New translations strings.xml (Armenian) 2024-11-07 11:53:04 +01:00
Eugen Rochko
f1140a0197 New translations strings.xml (Hungarian) 2024-11-07 11:53:03 +01:00
Eugen Rochko
179534e931 New translations strings.xml (Greek) 2024-11-07 11:52:59 +01:00
Eugen Rochko
be2db34586 New translations strings.xml (German) 2024-11-07 11:52:58 +01:00
Eugen Rochko
50b81c3b98 New translations strings.xml (Danish) 2024-11-07 11:52:57 +01:00
Eugen Rochko
31ae0b6e08 New translations strings.xml (Czech) 2024-11-07 11:52:56 +01:00
Eugen Rochko
36fdecd22e New translations strings.xml (Belarusian) 2024-11-07 11:52:53 +01:00
Eugen Rochko
d33f1d59ca New translations strings.xml (Spanish) 2024-11-07 11:52:52 +01:00
Eugen Rochko
b6a978f376 New translations strings.xml (French) 2024-11-07 11:52:50 +01:00
Eugen Rochko
a1da9be14f New translations strings.xml (Frisian) 2024-11-07 11:52:48 +01:00
Eugen Rochko
692ebed8fb New translations strings.xml (Icelandic) 2024-11-07 11:52:47 +01:00
Eugen Rochko
000294d2fa New translations strings.xml (Basque) 2024-11-07 11:52:46 +01:00
Grishka
6406d25938 oops 2024-11-07 13:46:25 +03:00
Grishka
9c95d5f6e5 Make favorites and bookmarks a tab in profile (AND-135) 2024-11-07 13:24:40 +03:00
Eugen Rochko
c15ef07d53 New translations strings.xml (Russian) 2024-11-06 12:56:23 +01:00
Eugen Rochko
7182647574 New translations strings.xml (Icelandic) 2024-11-06 12:56:22 +01:00
Eugen Rochko
2a08b27667 New translations strings.xml (Swedish) 2024-11-06 10:06:02 +01:00
Grishka
56a2510564 Show mutual followers in profile (AND-187) 2024-11-06 11:56:04 +03:00
Grishka
ddaab49976 Support "new post" push notifications
fixes #910
2024-11-06 10:25:21 +03:00
Eugen Rochko
508ea32701 New translations strings.xml (Portuguese, Brazilian) 2024-11-05 22:46:34 +01:00
Grishka
1b17600835 Group settings by account (AND-170) 2024-11-05 23:05:33 +03:00
Grishka
c60d06950f Crash fixes 2024-11-05 20:45:49 +03:00
Eugen Rochko
bbdc3d4038 New translations strings.xml (Italian) 2024-11-05 17:49:45 +01:00
Eugen Rochko
5e2a292aeb New translations strings.xml (Thai) 2024-11-03 20:20:52 +01:00
Eugen Rochko
1f6c48edf8 New translations strings.xml (Thai) 2024-11-03 19:12:56 +01:00
Eugen Rochko
a72acf7d32 New translations strings.xml (German) 2024-11-03 12:51:41 +01:00
Grishka
162bc86ebe Merge branch 'l10n_master' 2024-11-02 11:20:36 +03:00
Grishka
af8f042f10 Add changelog 2024-11-02 11:20:18 +03:00
Eugen Rochko
7aae8b03af New translations strings.xml (Vietnamese) 2024-11-01 15:38:16 +01:00
Grishka
b28c095226 Fix dynamic colors setting 2024-11-01 10:45:41 +03:00
Eugen Rochko
9432fc9b8c New translations strings.xml (Chinese Traditional) 2024-11-01 03:09:45 +01:00
Eugen Rochko
37df47c7cd New translations strings.xml (Russian) 2024-10-31 13:22:11 +01:00
Grishka
62602839db Merge branch 'l10n_master' 2024-10-31 15:13:13 +03:00
Eugen Rochko
52c56db1ce New translations strings.xml (Russian) 2024-10-31 10:26:24 +01:00
Eugen Rochko
cdc3b37ee4 New translations strings.xml (Swedish) 2024-10-31 09:15:57 +01:00
Grishka
46bd36b65d And more colors 2024-10-31 10:22:55 +03:00
Grishka
70eb5bf68c Fix more colors 2024-10-31 10:18:34 +03:00
Grishka
c2f6b16aff Support grouping follow notifications (AND-230) 2024-10-31 10:09:42 +03:00
Grishka
603c058ec9 Allow disabling dynamic colors on Android 12+ (AND-143) 2024-10-31 10:05:25 +03:00
Grishka
3582d7bdad Fix colors in high-contrast modes 2024-10-31 09:24:26 +03:00
Grishka
d988e1aecf Assorted minor fixes 2024-10-31 08:55:28 +03:00
Grishka
7bf322d48a Crash fix 2024-10-31 08:28:14 +03:00
Eugen Rochko
5c4a450ef0 New translations strings.xml (Belarusian) 2024-10-30 20:51:38 +01:00
Eugen Rochko
c370fab1b4 New translations strings.xml (Belarusian) 2024-10-30 19:55:52 +01:00
Eugen Rochko
c79cba96ec New translations strings.xml (Chinese Traditional) 2024-10-30 17:05:32 +01:00
Eugen Rochko
ca4aed3dc2 New translations full_description.txt (Scottish Gaelic) 2024-10-30 13:33:29 +01:00
Eugen Rochko
c20237d32c New translations strings.xml (Scottish Gaelic) 2024-10-30 13:33:28 +01:00
Grishka
6082a0bcd8 Provide URLs for the link button thing in system app switcher
closes #632
2024-10-30 14:27:44 +03:00
Grishka
3de494f9e9 Avatar cropping (AND-203)
closes #76
2024-10-30 13:39:06 +03:00
Grishka
1b6c299251 Fix custom emoji keyboard 2024-10-30 09:20:35 +03:00
Grishka
01ae5b915d oops I forgot the copy link thing 2024-10-30 05:55:04 +03:00
Eugen Rochko
d0ca465194 New translations strings.xml (Spanish) 2024-10-29 18:25:05 +01:00
Eugen Rochko
07564f2964 New translations strings.xml (Italian) 2024-10-29 11:13:11 +01:00
Grishka
eb45b59cac Fix gap loading for real this time 2024-10-29 05:48:48 +03:00
Eugen Rochko
6e4c4c86f6 New translations strings.xml (Chinese Traditional) 2024-10-28 19:07:33 +01:00
Eugen Rochko
b52dd603a1 New translations full_description.txt (Icelandic) 2024-10-28 14:51:47 +01:00
Eugen Rochko
573e13f39f New translations strings.xml (Icelandic) 2024-10-28 14:51:45 +01:00
Grishka
5848dc0e67 oops 2024-10-28 11:53:42 +03:00
Eugen Rochko
7ae5546113 New translations strings.xml (Interlingua) 2024-10-28 09:41:58 +01:00
Eugen Rochko
a126a078b4 New translations strings.xml (Kabyle) 2024-10-28 09:41:56 +01:00
Eugen Rochko
808dab6f50 New translations strings.xml (Occitan) 2024-10-28 09:41:54 +01:00
Eugen Rochko
70dc5aece0 New translations strings.xml (Scottish Gaelic) 2024-10-28 09:41:53 +01:00
Eugen Rochko
80f76d0f05 New translations strings.xml (Sinhala) 2024-10-28 09:41:51 +01:00
Eugen Rochko
d2a96af886 New translations strings.xml (Bosnian) 2024-10-28 09:41:50 +01:00
Eugen Rochko
6b6e720ca5 New translations strings.xml (Filipino) 2024-10-28 09:41:49 +01:00
Eugen Rochko
9eacb7b067 New translations strings.xml (Welsh) 2024-10-28 09:41:48 +01:00
Eugen Rochko
36cce87ffc New translations strings.xml (Burmese) 2024-10-28 09:41:46 +01:00
Eugen Rochko
b028c3ad38 New translations strings.xml (Hindi) 2024-10-28 09:41:45 +01:00
Eugen Rochko
eada060f57 New translations strings.xml (Croatian) 2024-10-28 09:41:44 +01:00
Eugen Rochko
53cfbcb5b0 New translations strings.xml (Thai) 2024-10-28 09:41:43 +01:00
Eugen Rochko
23c624f575 New translations strings.xml (Bengali) 2024-10-28 09:41:42 +01:00
Eugen Rochko
669f3a50c8 New translations strings.xml (Persian) 2024-10-28 09:41:41 +01:00
Eugen Rochko
fa3f4f6eda New translations strings.xml (Indonesian) 2024-10-28 09:41:40 +01:00
Eugen Rochko
d97ffc32aa New translations strings.xml (Portuguese, Brazilian) 2024-10-28 09:41:38 +01:00
Eugen Rochko
1aecf4021f New translations strings.xml (Galician) 2024-10-28 09:41:37 +01:00
Eugen Rochko
f3d76a26f7 New translations strings.xml (Vietnamese) 2024-10-28 09:41:35 +01:00
Eugen Rochko
e5dc62db6f New translations strings.xml (Chinese Traditional) 2024-10-28 09:41:34 +01:00
Eugen Rochko
6008368045 New translations strings.xml (Chinese Simplified) 2024-10-28 09:41:33 +01:00
Eugen Rochko
83af61a758 New translations strings.xml (Ukrainian) 2024-10-28 09:41:31 +01:00
Eugen Rochko
eefcc34277 New translations strings.xml (Turkish) 2024-10-28 09:41:30 +01:00
Eugen Rochko
4a65976eea New translations strings.xml (Swedish) 2024-10-28 09:41:29 +01:00
Eugen Rochko
cb8aea258a New translations strings.xml (Slovenian) 2024-10-28 09:41:28 +01:00
Eugen Rochko
e5297b023d New translations strings.xml (Slovak) 2024-10-28 09:41:26 +01:00
Eugen Rochko
21c6f41013 New translations strings.xml (Russian) 2024-10-28 09:41:25 +01:00
Eugen Rochko
19f8d908c7 New translations strings.xml (Portuguese) 2024-10-28 09:41:24 +01:00
Eugen Rochko
fae7f73f7a New translations strings.xml (Polish) 2024-10-28 09:41:22 +01:00
Eugen Rochko
41da8cc1d7 New translations strings.xml (Norwegian) 2024-10-28 09:41:21 +01:00
Eugen Rochko
39d5a32494 New translations strings.xml (Dutch) 2024-10-28 09:41:20 +01:00
Eugen Rochko
c885b5a85e New translations strings.xml (Lithuanian) 2024-10-28 09:41:19 +01:00
Eugen Rochko
76f2b63171 New translations strings.xml (Korean) 2024-10-28 09:41:17 +01:00
Eugen Rochko
58e35d8da3 New translations strings.xml (Georgian) 2024-10-28 09:41:16 +01:00
Eugen Rochko
a5e03357df New translations strings.xml (Japanese) 2024-10-28 09:41:15 +01:00
Eugen Rochko
5a7ab6be70 New translations strings.xml (Italian) 2024-10-28 09:41:14 +01:00
Eugen Rochko
e977b46392 New translations strings.xml (Armenian) 2024-10-28 09:41:13 +01:00
Eugen Rochko
66de2f4b87 New translations strings.xml (Hungarian) 2024-10-28 09:41:11 +01:00
Eugen Rochko
1a48277cf2 New translations strings.xml (Finnish) 2024-10-28 09:41:08 +01:00
Eugen Rochko
6a55bd2248 New translations strings.xml (Greek) 2024-10-28 09:41:07 +01:00
Eugen Rochko
3a82395428 New translations strings.xml (German) 2024-10-28 09:41:06 +01:00
Eugen Rochko
a98b93feec New translations strings.xml (Danish) 2024-10-28 09:41:04 +01:00
Eugen Rochko
0cff2658f3 New translations strings.xml (Czech) 2024-10-28 09:41:03 +01:00
Eugen Rochko
d3d95d49de New translations strings.xml (Catalan) 2024-10-28 09:41:02 +01:00
Eugen Rochko
71ca9b6f3d New translations strings.xml (Belarusian) 2024-10-28 09:41:01 +01:00
Eugen Rochko
bf9c3d4d8d New translations strings.xml (Arabic) 2024-10-28 09:40:59 +01:00
Eugen Rochko
4b304629b7 New translations strings.xml (Spanish) 2024-10-28 09:40:58 +01:00
Eugen Rochko
c4314f100e New translations strings.xml (French) 2024-10-28 09:40:57 +01:00
Eugen Rochko
14c250446c New translations strings.xml (Frisian) 2024-10-28 09:40:55 +01:00
Eugen Rochko
8bc1c8e79c New translations strings.xml (Icelandic) 2024-10-28 09:40:54 +01:00
Eugen Rochko
5e6781817d New translations strings.xml (Basque) 2024-10-28 09:40:53 +01:00
Grishka
5b5e4fbbd2 Remove unused resources 2024-10-28 11:30:48 +03:00
Grishka
3dcc6d0013 Media viewer redesign (AND-196) 2024-10-28 11:26:40 +03:00
Grishka
2ad50cd972 Allow returning to previous scroll position in home timeline (AND-189) 2024-10-27 05:38:15 +03:00
Grishka
ced5fe4ee0 Revert "fix"
This reverts commit db4afd4c8f.
2024-10-27 04:33:48 +03:00
Grishka
db4afd4c8f fix 2024-10-26 07:21:45 +03:00
Grishka
a0d3bd83f2 Fix possible post duplicates in home timeline 2024-10-26 07:11:31 +03:00
Grishka
2092a6b8fe Fix new posts button dismiss gesture 2024-10-26 06:47:43 +03:00
Grishka
ad04433944 Load timeline gaps depending on scroll direction (AND-190)
Closes #70, closes #154, closes #147, closes #281
2024-10-26 06:45:01 +03:00
Grishka
57da77b642 Disable overscrolling in account switcher sheet (AND-207) 2024-10-25 05:17:40 +03:00
Grishka
f80e3771d1 Make toolbar scroll away in home timeline (AND-208) 2024-10-25 05:10:07 +03:00
Grishka
6a18d8ef03 Replace characters Android doesn't like (AND-193), fix #890 2024-10-25 04:37:11 +03:00
Grishka
a312018441 Open old file picker by long-pressing "add media" button (AND-194) 2024-10-25 04:31:54 +03:00
Grishka
3026bd5c51 Support for Android 15's color contrast setting WIP 2024-10-25 02:40:33 +03:00
Eugen Rochko
5afde48052 New translations strings.xml (Icelandic) 2024-10-24 17:29:09 +02:00
Grishka
14209dc785 Assorted crash fixes 2024-10-24 02:31:05 +03:00
Grishka
f1b30f251c Improve rendering of block elements in rich text
fixes #907
2024-10-24 01:37:28 +03:00
Eugen Rochko
6a849d654f New translations strings.xml (Frisian) 2024-10-19 16:50:00 +02:00
Eugen Rochko
2f9c5fe210 New translations strings.xml (Basque) 2024-10-18 00:48:18 +02:00
Eugen Rochko
43f096420f New translations strings.xml (Icelandic) 2024-10-16 12:12:44 +02:00
Eugen Rochko
5b848ed1ca New translations strings.xml (Russian) 2024-10-13 10:05:10 +02:00
Eugen Rochko
9e1cf330d7 New translations strings.xml (Greek) 2024-10-12 09:39:28 +02:00
Grishka
1ad2d08e27 Merge branch 'l10n_master' 2024-10-10 04:09:47 +03:00
Grishka
42658add38 Fix opening links in non-browser apps 2024-10-10 04:09:20 +03:00
Grishka
b211789847 Fix colors for quotes and code blocks 2024-10-10 01:29:21 +03:00
Eugen Rochko
9c88183366 New translations strings.xml (Russian) 2024-10-09 20:16:06 +02:00
Eugen Rochko
c76dba3a8c New translations strings.xml (Basque) 2024-10-09 18:07:53 +02:00
Eugen Rochko
29bee87f2a New translations strings.xml (Basque) 2024-10-09 16:54:04 +02:00
Grishka
c139f85b99 Fix wrong unread notification count for some accounts on 4.3 2024-10-09 06:09:53 +03:00
Grishka
3247d4f2f5 Fix notifications loading on pre-4.3 servers
fixes #897
2024-10-09 05:28:01 +03:00
Grishka
77b2f98f17 Quotes in text formatting (AND-222) 2024-10-09 05:20:58 +03:00
Grishka
82c6c8076a Lists in text formatting (AND-221) 2024-10-09 03:00:37 +03:00
Grishka
4177faa553 Monospace text formatting (AND-223) 2024-10-09 01:21:50 +03:00
Eugen Rochko
92ec125661 New translations strings.xml (Indonesian) 2024-10-08 12:59:00 +02:00
Grishka
513a57663b Display bold, italic, and strikethrough formatting (AND-220, AND-224) 2024-10-07 18:48:06 +03:00
Eugen Rochko
20e7f716f1 New translations strings.xml (Chinese Simplified) 2024-10-07 08:00:50 +02:00
Grishka
71f92cb66c Bump version 2024-10-06 01:25:21 +03:00
Grishka
77b2abd0cb Merge branch 'l10n_master' 2024-10-06 01:24:29 +03:00
Grishka
15385dd924 Make fastlane create draft releases 2024-10-06 01:22:25 +03:00
Grishka
08847ec641 Always reset notifications marker on "mark as read"
fixes #897
2024-10-06 01:11:21 +03:00
Grishka
805fc5d8c7 Crash fix 2024-10-06 01:06:45 +03:00
Eugen Rochko
3d7a95d336 New translations strings.xml (German) 2024-10-05 09:01:18 +02:00
Eugen Rochko
c1869386ff New translations strings.xml (German) 2024-10-05 07:34:09 +02:00
Eugen Rochko
7a728c52cf New translations strings.xml (German) 2024-10-04 21:23:57 +02:00
Eugen Rochko
22f3aad538 New translations strings.xml (Frisian) 2024-10-04 18:40:52 +02:00
Eugen Rochko
42da6dcf48 New translations strings.xml (Dutch) 2024-10-04 18:40:50 +02:00
Eugen Rochko
c0f18b1f61 New translations strings.xml (Frisian) 2024-10-04 17:34:12 +02:00
Grishka
492d851d89 Merge branch 'l10n_master' 2024-10-04 00:26:56 +03:00
Grishka
853f9dc8e4 Assorted crash fixes
fixes #896
2024-10-04 00:26:23 +03:00
Eugen Rochko
0e2ae4d3c0 New translations strings.xml (Italian) 2024-10-03 23:12:01 +02:00
Eugen Rochko
3ea1412faa New translations full_description.txt (Persian) 2024-10-02 21:38:56 +02:00
Eugen Rochko
e83f0749ee New translations full_description.txt (Persian) 2024-10-02 19:59:42 +02:00
Eugen Rochko
343d958677 New translations strings.xml (Persian) 2024-10-02 19:59:41 +02:00
Eugen Rochko
2f32378978 New translations strings.xml (Dutch) 2024-10-02 19:59:40 +02:00
Eugen Rochko
cfc5683f75 New translations strings.xml (Dutch) 2024-10-02 18:41:01 +02:00
Eugen Rochko
823e2f6ac6 New translations short_description.txt (Turkish) 2024-10-02 15:19:46 +02:00
Eugen Rochko
5f5fcdde46 New translations full_description.txt (Turkish) 2024-10-02 15:19:45 +02:00
Eugen Rochko
cf74e252ce New translations strings.xml (Turkish) 2024-10-02 15:19:44 +02:00
Eugen Rochko
010ca587d2 New translations strings.xml (Turkish) 2024-10-02 13:21:57 +02:00
Eugen Rochko
2957ac813f New translations full_description.txt (Turkish) 2024-10-02 12:08:45 +02:00
Eugen Rochko
5aa117e2e3 New translations strings.xml (Turkish) 2024-10-02 12:08:44 +02:00
Eugen Rochko
f1df4e72d2 New translations strings.xml (Turkish) 2024-10-02 09:45:42 +02:00
Eugen Rochko
afee257211 New translations strings.xml (Turkish) 2024-10-02 08:32:27 +02:00
Grishka
74986a10f6 Fix crash. This is getting annoying. 2024-10-01 23:48:35 +03:00
Grishka
77b6344032 Fix account data migration for real 2024-10-01 23:19:48 +03:00
Grishka
cb0d7e73d4 Fix proguard shit again 2024-10-01 21:50:38 +03:00
Grishka
1b714e5815 Prepare a new release 2024-10-01 21:12:59 +03:00
Grishka
e5dd97f992 Merge branch 'l10n_master' 2024-10-01 21:11:45 +03:00
Grishka
2a7838f2a7 Crash fix 2024-10-01 20:46:11 +03:00
Grishka
25112c1fe3 Refresh FCM token every 30 days
Fixes #892
2024-10-01 20:36:25 +03:00
Grishka
e7850dfcfb Fix Token field requirements 2024-10-01 20:29:09 +03:00
Eugen Rochko
bbdece33ea New translations strings.xml (Lithuanian) 2024-10-01 18:11:26 +02:00
Eugen Rochko
f861eefe78 New translations strings.xml (Lithuanian) 2024-10-01 16:41:14 +02:00
Eugen Rochko
07e4c6d0a9 New translations full_description.txt (Lithuanian) 2024-10-01 14:16:23 +02:00
Eugen Rochko
fd1afc8c02 New translations strings.xml (Lithuanian) 2024-10-01 14:16:22 +02:00
Eugen Rochko
a008c025f5 New translations strings.xml (Lithuanian) 2024-10-01 12:53:42 +02:00
Eugen Rochko
c4768e7f87 New translations strings.xml (Spanish) 2024-10-01 00:25:26 +02:00
Eugen Rochko
812ea1023e New translations strings.xml (Spanish) 2024-09-30 22:10:15 +02:00
Eugen Rochko
e74e45f315 New translations strings.xml (Spanish) 2024-09-29 22:05:21 +02:00
Eugen Rochko
b590b23439 New translations strings.xml (Spanish) 2024-09-29 21:02:44 +02:00
Eugen Rochko
a8208b4c05 New translations strings.xml (Thai) 2024-09-28 22:35:55 +02:00
Eugen Rochko
c742b695e3 New translations full_description.txt (Japanese) 2024-09-28 20:36:01 +02:00
Eugen Rochko
9a8ff82f2d New translations strings.xml (Thai) 2024-09-28 20:36:00 +02:00
Eugen Rochko
3b2f495a50 New translations full_description.txt (Japanese) 2024-09-28 19:27:45 +02:00
Eugen Rochko
773d5a104b New translations strings.xml (Basque) 2024-09-27 04:13:48 +02:00
Eugen Rochko
c4ac325c14 New translations strings.xml (Basque) 2024-09-27 03:10:49 +02:00
Eugen Rochko
8964f22c0c New translations strings.xml (Basque) 2024-09-26 21:58:40 +02:00
Eugen Rochko
6b99cc48a4 New translations full_description.txt (Persian) 2024-09-26 20:42:25 +02:00
Eugen Rochko
448949d5c2 New translations full_description.txt (Persian) 2024-09-26 19:32:09 +02:00
Eugen Rochko
e94f508680 New translations full_description.txt (Persian) 2024-09-25 21:38:40 +02:00
Eugen Rochko
a3472d0e1c New translations full_description.txt (Persian) 2024-09-25 19:14:57 +02:00
Eugen Rochko
3ebb058a62 New translations strings.xml (Persian) 2024-09-25 19:14:56 +02:00
Eugen Rochko
32fd14b3ea New translations short_description.txt (Persian) 2024-09-25 17:17:32 +02:00
Eugen Rochko
49c1f14a20 New translations full_description.txt (Persian) 2024-09-25 17:17:31 +02:00
Eugen Rochko
7dea64676e New translations strings.xml (Persian) 2024-09-25 17:17:30 +02:00
Eugen Rochko
a77142a9ee New translations strings.xml (Slovak) 2024-09-25 13:32:51 +02:00
Eugen Rochko
898ef9a560 New translations strings.xml (Japanese) 2024-09-24 17:38:33 +02:00
Eugen Rochko
47539ac47e New translations strings.xml (Japanese) 2024-09-24 15:54:13 +02:00
Eugen Rochko
5aac227ad6 New translations strings.xml (Chinese Traditional) 2024-09-23 15:22:48 +02:00
Eugen Rochko
38c8990f4e New translations strings.xml (Italian) 2024-09-23 15:22:47 +02:00
Eugen Rochko
797a967cb1 New translations strings.xml (Italian) 2024-09-23 12:18:00 +02:00
Eugen Rochko
0d7a5e55fe New translations strings.xml (Spanish) 2024-09-22 15:14:22 +02:00
Eugen Rochko
87de48c957 New translations strings.xml (Vietnamese) 2024-09-22 12:25:22 +02:00
Eugen Rochko
3489d8d5b3 New translations strings.xml (Vietnamese) 2024-09-22 11:28:35 +02:00
Eugen Rochko
aa6c3c56bb New translations strings.xml (Portuguese, Brazilian) 2024-09-21 11:48:22 +02:00
Eugen Rochko
3fdf3dcdab New translations strings.xml (Ukrainian) 2024-09-21 11:48:21 +02:00
Eugen Rochko
2f716d63de New translations strings.xml (Interlingua) 2024-09-21 10:23:51 +02:00
Eugen Rochko
bbe71fff51 New translations strings.xml (Urdu (India)) 2024-09-21 10:23:49 +02:00
Eugen Rochko
74ae04e0d2 New translations strings.xml (Kabyle) 2024-09-21 10:23:49 +02:00
Eugen Rochko
bb293ec319 New translations strings.xml (Igbo) 2024-09-21 10:23:48 +02:00
Eugen Rochko
bf6f8a7137 New translations strings.xml (Occitan) 2024-09-21 10:23:47 +02:00
Eugen Rochko
8080986e5b New translations strings.xml (Scottish Gaelic) 2024-09-21 10:23:46 +02:00
Eugen Rochko
5ed24a227e New translations strings.xml (Sinhala) 2024-09-21 10:23:44 +02:00
Eugen Rochko
2d89b4b539 New translations strings.xml (Bosnian) 2024-09-21 10:23:43 +02:00
Eugen Rochko
378a675157 New translations strings.xml (Filipino) 2024-09-21 10:23:42 +02:00
Eugen Rochko
127662967a New translations strings.xml (Burmese) 2024-09-21 10:23:41 +02:00
Eugen Rochko
76b52dc06e New translations strings.xml (Hindi) 2024-09-21 10:23:40 +02:00
Eugen Rochko
55d3b127e7 New translations strings.xml (Croatian) 2024-09-21 10:23:39 +02:00
Eugen Rochko
0f9e0fe140 New translations strings.xml (Thai) 2024-09-21 10:23:38 +02:00
Eugen Rochko
2b462f7289 New translations strings.xml (Bengali) 2024-09-21 10:23:37 +02:00
Eugen Rochko
977ca60655 New translations strings.xml (Persian) 2024-09-21 10:23:36 +02:00
Eugen Rochko
309b8089b8 New translations strings.xml (Indonesian) 2024-09-21 10:23:35 +02:00
Eugen Rochko
0563068ec3 New translations strings.xml (Portuguese, Brazilian) 2024-09-21 10:23:34 +02:00
Eugen Rochko
e33282d686 New translations strings.xml (Icelandic) 2024-09-21 10:23:33 +02:00
Eugen Rochko
0b83b9b5e0 New translations strings.xml (Galician) 2024-09-21 10:23:31 +02:00
Eugen Rochko
8abb4d25f9 New translations strings.xml (Chinese Traditional) 2024-09-21 10:23:30 +02:00
Eugen Rochko
aadf404142 New translations strings.xml (Chinese Simplified) 2024-09-21 10:23:29 +02:00
Eugen Rochko
8a608a1e71 New translations strings.xml (Turkish) 2024-09-21 10:23:28 +02:00
Eugen Rochko
5571220b20 New translations strings.xml (Swedish) 2024-09-21 10:23:27 +02:00
Eugen Rochko
05c831a8b1 New translations strings.xml (Slovenian) 2024-09-21 10:23:25 +02:00
Eugen Rochko
c237b36f8b New translations strings.xml (Slovak) 2024-09-21 10:23:24 +02:00
Eugen Rochko
2ed7fdecb4 New translations strings.xml (Russian) 2024-09-21 10:23:23 +02:00
Eugen Rochko
1dce9f1928 New translations strings.xml (Portuguese) 2024-09-21 10:23:22 +02:00
Eugen Rochko
4a6a707bbc New translations strings.xml (Polish) 2024-09-21 10:23:21 +02:00
Eugen Rochko
989095a13d New translations strings.xml (Norwegian) 2024-09-21 10:23:20 +02:00
Eugen Rochko
34556b0c45 New translations strings.xml (Korean) 2024-09-21 10:23:19 +02:00
Eugen Rochko
7aa4926ac3 New translations strings.xml (Georgian) 2024-09-21 10:23:18 +02:00
Eugen Rochko
189cee1395 New translations strings.xml (Italian) 2024-09-21 10:23:16 +02:00
Eugen Rochko
5a7b18983d New translations strings.xml (Armenian) 2024-09-21 10:23:15 +02:00
Eugen Rochko
72f01267ae New translations strings.xml (Hungarian) 2024-09-21 10:23:14 +02:00
Eugen Rochko
e5df4a3886 New translations strings.xml (Hebrew) 2024-09-21 10:23:13 +02:00
Eugen Rochko
3827047f05 New translations strings.xml (Irish) 2024-09-21 10:23:12 +02:00
Eugen Rochko
0f262c41ec New translations strings.xml (Finnish) 2024-09-21 10:23:11 +02:00
Eugen Rochko
2d2d405c73 New translations strings.xml (Basque) 2024-09-21 10:23:10 +02:00
Eugen Rochko
9b82c9bbe5 New translations strings.xml (Greek) 2024-09-21 10:23:09 +02:00
Eugen Rochko
8573276a79 New translations strings.xml (German) 2024-09-21 10:23:08 +02:00
Eugen Rochko
9f5f0d594c New translations strings.xml (Danish) 2024-09-21 10:23:07 +02:00
Eugen Rochko
a7bfaf732f New translations strings.xml (Czech) 2024-09-21 10:23:06 +02:00
Eugen Rochko
9b0af7d60d New translations strings.xml (Catalan) 2024-09-21 10:23:04 +02:00
Eugen Rochko
1dd937f047 New translations strings.xml (Belarusian) 2024-09-21 10:23:03 +02:00
Eugen Rochko
e135b61dd0 New translations strings.xml (Arabic) 2024-09-21 10:23:02 +02:00
Eugen Rochko
8c3687ca4a New translations strings.xml (Romanian) 2024-09-21 10:23:01 +02:00
Eugen Rochko
3ceea6a83b New translations strings.xml (Lithuanian) 2024-09-21 10:23:00 +02:00
Eugen Rochko
cc22ccfb66 New translations strings.xml (Frisian) 2024-09-21 10:22:59 +02:00
Eugen Rochko
d1c4ca38ff New translations strings.xml (Dutch) 2024-09-21 10:22:58 +02:00
Eugen Rochko
52fb35e5e9 New translations strings.xml (French) 2024-09-21 10:22:56 +02:00
Eugen Rochko
2b0faf0e23 New translations strings.xml (Ukrainian) 2024-09-21 10:22:55 +02:00
Eugen Rochko
bc74a72369 New translations strings.xml (Vietnamese) 2024-09-21 10:22:54 +02:00
Eugen Rochko
0c2e4e34fe New translations strings.xml (Spanish) 2024-09-21 10:22:53 +02:00
Eugen Rochko
67bd2e9629 New translations strings.xml (Japanese) 2024-09-21 10:22:52 +02:00
Eugen Rochko
d9dfd6e1bb New translations strings.xml (Welsh) 2024-09-21 10:22:51 +02:00
Grishka
1dc9adafc7 Add moderation_warning notifications (AND-175) 2024-09-21 11:09:36 +03:00
Grishka
9e201f3c00 fix 2024-09-21 10:43:24 +03:00
Grishka
16e2632d9b Add severed_relationships notifications (AND-174) 2024-09-21 10:40:04 +03:00
Grishka
9533b4f45d Fix layout for single-line notification header + inline status 2024-09-21 09:47:50 +03:00
Grishka
de83c1ea96 Add update notifications (AND-173) 2024-09-21 09:22:41 +03:00
Grishka
18b5c8ed50 Add "just posted" header for new status notifications 2024-09-21 07:41:45 +03:00
Eugen Rochko
14f7f5a1f4 New translations strings.xml (Chinese Traditional) 2024-09-21 06:18:56 +02:00
Eugen Rochko
4960589bef New translations strings.xml (Swedish) 2024-09-21 01:34:11 +02:00
Eugen Rochko
e2c7f8c7f0 New translations strings.xml (Italian) 2024-09-20 23:52:20 +02:00
Eugen Rochko
1371260fdf New translations strings.xml (German) 2024-09-20 15:47:30 +02:00
Eugen Rochko
01c816814a New translations strings.xml (Portuguese, Brazilian) 2024-09-20 13:06:18 +02:00
Eugen Rochko
bbb61e7a87 New translations strings.xml (Interlingua) 2024-09-20 11:13:12 +02:00
Eugen Rochko
30b24384d5 New translations strings.xml (Scottish Gaelic) 2024-09-20 11:13:08 +02:00
Eugen Rochko
506df71b37 New translations strings.xml (Hindi) 2024-09-20 11:13:04 +02:00
Eugen Rochko
bb323ab08f New translations strings.xml (Thai) 2024-09-20 11:13:02 +02:00
Eugen Rochko
6d8cb8cbb4 New translations strings.xml (Persian) 2024-09-20 11:13:00 +02:00
Eugen Rochko
90dc391b99 New translations strings.xml (Indonesian) 2024-09-20 11:12:58 +02:00
Eugen Rochko
8b974c2e96 New translations strings.xml (Portuguese, Brazilian) 2024-09-20 11:12:57 +02:00
Eugen Rochko
baa0f2ba33 New translations strings.xml (Icelandic) 2024-09-20 11:12:56 +02:00
Eugen Rochko
697fc713a0 New translations strings.xml (Galician) 2024-09-20 11:12:55 +02:00
Eugen Rochko
1704f8079f New translations strings.xml (Chinese Traditional) 2024-09-20 11:12:54 +02:00
Eugen Rochko
7c1fd70569 New translations strings.xml (Chinese Simplified) 2024-09-20 11:12:52 +02:00
Eugen Rochko
dd19d1408b New translations strings.xml (Turkish) 2024-09-20 11:12:51 +02:00
Eugen Rochko
f36bd866f0 New translations strings.xml (Swedish) 2024-09-20 11:12:50 +02:00
Eugen Rochko
6311920b4c New translations strings.xml (Slovenian) 2024-09-20 11:12:49 +02:00
Eugen Rochko
5cf20658bb New translations strings.xml (Slovak) 2024-09-20 11:12:48 +02:00
Eugen Rochko
c5c1015231 New translations strings.xml (Russian) 2024-09-20 11:12:46 +02:00
Eugen Rochko
2fb45b5384 New translations strings.xml (Portuguese) 2024-09-20 11:12:45 +02:00
Eugen Rochko
b6e1304df0 New translations strings.xml (Polish) 2024-09-20 11:12:43 +02:00
Eugen Rochko
f0ed251438 New translations strings.xml (Norwegian) 2024-09-20 11:12:42 +02:00
Eugen Rochko
0f2d218956 New translations strings.xml (Georgian) 2024-09-20 11:12:40 +02:00
Eugen Rochko
0756883af9 New translations strings.xml (Italian) 2024-09-20 11:12:39 +02:00
Eugen Rochko
d76612f0b9 New translations strings.xml (Armenian) 2024-09-20 11:12:38 +02:00
Eugen Rochko
3c85421474 New translations strings.xml (Hungarian) 2024-09-20 11:12:36 +02:00
Eugen Rochko
cba8050989 New translations strings.xml (Finnish) 2024-09-20 11:12:34 +02:00
Eugen Rochko
5060409597 New translations strings.xml (Basque) 2024-09-20 11:12:33 +02:00
Eugen Rochko
e80d711738 New translations strings.xml (Greek) 2024-09-20 11:12:31 +02:00
Eugen Rochko
903a5477a7 New translations strings.xml (German) 2024-09-20 11:12:30 +02:00
Eugen Rochko
b7940df425 New translations strings.xml (Danish) 2024-09-20 11:12:29 +02:00
Eugen Rochko
6b2685618d New translations strings.xml (Czech) 2024-09-20 11:12:27 +02:00
Eugen Rochko
40c52c7df7 New translations strings.xml (Catalan) 2024-09-20 11:12:25 +02:00
Eugen Rochko
5b460fec39 New translations strings.xml (Belarusian) 2024-09-20 11:12:24 +02:00
Eugen Rochko
f0085cb240 New translations strings.xml (Arabic) 2024-09-20 11:12:22 +02:00
Eugen Rochko
477dd0b219 New translations strings.xml (Lithuanian) 2024-09-20 11:12:20 +02:00
Eugen Rochko
9b585e5955 New translations strings.xml (Frisian) 2024-09-20 11:12:19 +02:00
Eugen Rochko
9e7e540068 New translations strings.xml (Dutch) 2024-09-20 11:12:18 +02:00
Eugen Rochko
c1e5daec3d New translations strings.xml (French) 2024-09-20 11:12:16 +02:00
Eugen Rochko
ccc2c9d6d3 New translations strings.xml (Ukrainian) 2024-09-20 11:12:15 +02:00
Eugen Rochko
fbcad38d71 New translations strings.xml (Vietnamese) 2024-09-20 11:12:14 +02:00
Eugen Rochko
d487b3c114 New translations strings.xml (Spanish) 2024-09-20 11:12:13 +02:00
Eugen Rochko
62a5e36eec New translations strings.xml (Japanese) 2024-09-20 11:12:11 +02:00
Grishka
c6130e4d29 Add a debug option to force re-register FCM 2024-09-20 11:46:31 +03:00
Grishka
26f7a75628 Grouped notifications 2024-09-20 11:39:50 +03:00
Eugen Rochko
4110eb064a New translations short_description.txt (Russian) 2024-09-20 05:35:32 +02:00
Eugen Rochko
3e8c4a8443 New translations full_description.txt (Russian) 2024-09-20 05:35:31 +02:00
Eugen Rochko
b8fc674fe8 New translations strings.xml (Russian) 2024-09-20 05:35:30 +02:00
Eugen Rochko
cb123a178a New translations strings.xml (Russian) 2024-09-20 03:26:46 +02:00
Grishka
80323f8236 Add support for /api/v2/instance 2024-09-19 02:37:19 +03:00
Grishka
edc03642cc Fix corner rounding 2024-09-19 01:50:35 +03:00
Grishka
114c77a665 Inline statuses 2024-09-18 19:25:59 +03:00
Grishka
0627644019 Fix spoilers on retoots 2024-09-18 06:05:42 +03:00
Grishka
1874267b32 Fix paddings 2024-09-18 05:07:07 +03:00
Grishka
de763ab6f7 Reply lines 2024-09-18 04:59:12 +03:00
Grishka
ace0072118 Post redesign part 2 (AND-18) 2024-09-18 03:57:11 +03:00
Grishka
3820eee174 Post redesign part 1 2024-09-17 22:06:31 +03:00
Eugen Rochko
754cd807c0 New translations strings.xml (Icelandic) 2024-09-16 12:22:01 +02:00
Eugen Rochko
e3f4951f95 New translations full_description.txt (French) 2024-09-15 23:47:41 +02:00
Eugen Rochko
b321c4e479 New translations full_description.txt (French) 2024-09-15 22:09:51 +02:00
Grishka
192c634755 Migrate account and instance data to SQLite 2024-09-15 20:15:01 +03:00
Eugen Rochko
ef27200764 New translations strings.xml (Chinese Traditional) 2024-09-15 11:09:52 +02:00
Eugen Rochko
aa4932077b New translations strings.xml (Greek) 2024-09-15 10:14:33 +02:00
Eugen Rochko
6c87c4aa7c New translations strings.xml (Thai) 2024-09-15 09:09:37 +02:00
Eugen Rochko
59e6f6033a New translations strings.xml (Basque) 2024-09-14 19:50:14 +02:00
Eugen Rochko
82a0d046a7 New translations strings.xml (Spanish) 2024-09-14 18:39:20 +02:00
Eugen Rochko
c98f1d32e8 New translations full_description.txt (Portuguese) 2024-09-13 18:19:28 +02:00
Eugen Rochko
34698a5aa2 New translations strings.xml (Vietnamese) 2024-09-13 16:52:11 +02:00
Grishka
ee1a0cc666 Allow "new posts" button to be swiped away 2024-09-13 01:21:23 +03:00
Grishka
eda1526830 Show an overlay on image attachments that failed to load 2024-09-13 00:47:04 +03:00
Grishka
f5961c8077 Update appkit image loader 2024-09-13 00:12:13 +03:00
Eugen Rochko
7f03bdae2b New translations strings.xml (Frisian) 2024-09-12 14:33:18 +02:00
Eugen Rochko
38ac8f14fb New translations strings.xml (Frisian) 2024-09-12 13:11:41 +02:00
Eugen Rochko
7d7bfad3c0 New translations strings.xml (Frisian) 2024-09-10 15:38:43 +02:00
Grishka
81ac72e4eb Trim strings in donation campaigns 2024-09-10 13:43:48 +03:00
Grishka
e915aab2fb Add tooltips to emoji keyboard (closes #884) 2024-09-10 13:37:28 +03:00
Grishka
a92c903ffb Fix #876 2024-09-10 13:32:07 +03:00
Grishka
e174a7efd7 Force intent to default browser when opening things in browser
fixes #881
2024-09-10 13:23:57 +03:00
Grishka
9f4575f349 Handle the case when a post with CW is also filtered 2024-09-10 13:08:58 +03:00
Gregory K
9cbfb1a7f8 Merge pull request #867 from adillari/profile_tab_margin_fix
Adjust margins on profile tab to center icons together
2024-09-08 09:11:23 +03:00
Eugen Rochko
6db20a2cc1 New translations full_description.txt (Lithuanian) 2024-09-07 18:37:14 +02:00
Eugen Rochko
fe067cba13 New translations strings.xml (Lithuanian) 2024-09-07 17:42:10 +02:00
Eugen Rochko
c0b5d34aae New translations strings.xml (Lithuanian) 2024-09-07 15:14:38 +02:00
Eugen Rochko
ee15655fc7 New translations strings.xml (Lithuanian) 2024-09-07 14:15:30 +02:00
Eugen Rochko
34a9cd0614 New translations strings.xml (Lithuanian) 2024-09-07 13:15:44 +02:00
Eugen Rochko
44b46bd83c New translations strings.xml (Welsh) 2024-09-06 18:07:09 +02:00
Eugen Rochko
8fbe1ef444 New translations strings.xml (Welsh) 2024-09-06 16:28:05 +02:00
Eugen Rochko
61e8615907 New translations strings.xml (French) 2024-09-05 03:31:00 +02:00
Eugen Rochko
4eef3a3243 New translations full_description.txt (Frisian) 2024-09-03 18:05:20 +02:00
Eugen Rochko
8585dc2cd0 New translations strings.xml (Frisian) 2024-09-03 18:05:19 +02:00
Eugen Rochko
3647fcaa0b New translations full_description.txt (Frisian) 2024-09-03 16:50:49 +02:00
Eugen Rochko
184a211819 New translations strings.xml (Frisian) 2024-09-02 16:22:10 +02:00
Eugen Rochko
7d36b67652 New translations short_description.txt (Frisian) 2024-09-02 14:44:25 +02:00
Eugen Rochko
7e0f786a43 New translations full_description.txt (Frisian) 2024-09-02 14:44:24 +02:00
Eugen Rochko
0a8cec46c0 New translations strings.xml (Frisian) 2024-09-02 14:44:23 +02:00
Eugen Rochko
3cd558c44f New translations strings.xml (Dutch) 2024-09-02 13:04:53 +02:00
Eugen Rochko
4076067b3e New translations short_description.txt (French) 2024-09-01 14:10:37 +02:00
Eugen Rochko
b3593a0e30 New translations full_description.txt (French) 2024-09-01 14:10:36 +02:00
Eugen Rochko
1daede2c62 New translations strings.xml (French) 2024-09-01 12:29:56 +02:00
Eugen Rochko
fefe529438 New translations strings.xml (Ukrainian) 2024-08-31 17:18:03 +02:00
Eugen Rochko
ba59aa6147 New translations strings.xml (Vietnamese) 2024-08-31 06:33:49 +02:00
Eugen Rochko
c42edb3b94 New translations strings.xml (Spanish) 2024-08-30 01:50:06 +02:00
Eugen Rochko
d647d9edd1 New translations full_description.txt (Japanese) 2024-08-29 12:52:24 +02:00
Eugen Rochko
ed2d03b5de New translations strings.xml (Japanese) 2024-08-29 12:52:23 +02:00
Eugen Rochko
5e1b39bfd7 New translations short_description.txt (Welsh) 2024-08-27 01:29:11 +02:00
Eugen Rochko
dc60f4bb51 New translations full_description.txt (Welsh) 2024-08-27 01:29:10 +02:00
Eugen Rochko
6a5c564b99 New translations strings.xml (Welsh) 2024-08-27 01:29:09 +02:00
Eugen Rochko
8745e5d034 New translations strings.xml (Welsh) 2024-08-27 00:28:37 +02:00
Eugen Rochko
448a12f2ed New translations short_description.txt (Welsh) 2024-08-26 00:50:10 +02:00
Eugen Rochko
e6cc15879e New translations full_description.txt (Welsh) 2024-08-26 00:50:09 +02:00
Eugen Rochko
76fd8686b3 New translations strings.xml (Welsh) 2024-08-26 00:50:08 +02:00
Eugen Rochko
2dbc282769 New translations full_description.txt (Thai) 2024-08-25 11:26:34 +02:00
Eugen Rochko
4fca4ca332 New translations full_description.txt (Thai) 2024-08-25 09:27:24 +02:00
Eugen Rochko
a18ed46151 New translations strings.xml (Lithuanian) 2024-08-22 18:11:54 +02:00
Eugen Rochko
07d9ee00ff New translations strings.xml (Lithuanian) 2024-08-22 16:50:59 +02:00
Eugen Rochko
5789c3af29 New translations strings.xml (Norwegian) 2024-08-22 00:45:26 +02:00
Eugen Rochko
d9a1ef059d New translations strings.xml (Norwegian) 2024-08-21 23:49:42 +02:00
Eugen Rochko
7148d95830 New translations strings.xml (Greek) 2024-08-19 13:26:10 +02:00
Eugen Rochko
9bfaa5db34 New translations short_description.txt (Indonesian) 2024-08-19 11:23:00 +02:00
Eugen Rochko
54a4d327ec New translations strings.xml (Indonesian) 2024-08-19 11:22:59 +02:00
Eugen Rochko
90bf1113f9 New translations full_description.txt (Indonesian) 2024-08-19 11:22:57 +02:00
Eugen Rochko
7cc23856f7 New translations full_description.txt (Indonesian) 2024-08-19 09:35:09 +02:00
Eugen Rochko
09158f7036 New translations strings.xml (Swedish) 2024-08-18 22:10:20 +02:00
Eugen Rochko
687880bbd5 New translations strings.xml (Slovenian) 2024-08-18 18:11:15 +02:00
Eugen Rochko
598f1fc3b3 New translations strings.xml (Danish) 2024-08-18 14:30:58 +02:00
Eugen Rochko
7989fa2853 New translations strings.xml (Lithuanian) 2024-08-18 12:30:21 +02:00
Eugen Rochko
f81f14fb5d New translations full_description.txt (Thai) 2024-08-18 10:11:25 +02:00
Eugen Rochko
4acf7a13f2 New translations short_description.txt (Thai) 2024-08-18 09:09:12 +02:00
Eugen Rochko
c004db7ac9 New translations full_description.txt (Thai) 2024-08-18 09:09:11 +02:00
Eugen Rochko
e39ac3ac18 New translations strings.xml (Danish) 2024-08-18 00:28:02 +02:00
Eugen Rochko
2011b08a2b New translations strings.xml (Danish) 2024-08-17 23:28:55 +02:00
Eugen Rochko
5afd82585e New translations strings.xml (Slovak) 2024-08-17 17:05:00 +02:00
Eugen Rochko
5daaf15195 New translations strings.xml (Slovak) 2024-08-17 15:50:17 +02:00
Eugen Rochko
d8c4247a2c New translations strings.xml (Lithuanian) 2024-08-17 12:10:13 +02:00
Eugen Rochko
627870098f New translations strings.xml (Danish) 2024-08-17 01:34:42 +02:00
Eugen Rochko
2a7a88466d New translations strings.xml (Danish) 2024-08-17 00:02:53 +02:00
Eugen Rochko
4d02d659e7 New translations strings.xml (Danish) 2024-08-16 22:43:38 +02:00
Eugen Rochko
86ab70757e New translations full_description.txt (Swedish) 2024-08-16 20:58:02 +02:00
Eugen Rochko
0161f71d63 New translations strings.xml (Swedish) 2024-08-16 20:58:01 +02:00
Eugen Rochko
7b5664cc8f New translations strings.xml (Slovak) 2024-08-16 20:58:00 +02:00
Eugen Rochko
6992ab4f02 New translations strings.xml (Slovak) 2024-08-16 12:35:19 +02:00
Eugen Rochko
88d8f7afc8 New translations strings.xml (Slovak) 2024-08-16 11:36:02 +02:00
Eugen Rochko
1a344f777d New translations strings.xml (Slovak) 2024-08-16 09:10:45 +02:00
Eugen Rochko
ff158c28cf New translations full_description.txt (Slovak) 2024-08-16 07:39:05 +02:00
Eugen Rochko
c39d2a8ec1 New translations strings.xml (Slovak) 2024-08-16 07:39:04 +02:00
Eugen Rochko
07d722dca3 New translations full_description.txt (Slovak) 2024-08-16 06:31:26 +02:00
Eugen Rochko
5db7a9df18 New translations strings.xml (Danish) 2024-08-16 04:11:10 +02:00
Eugen Rochko
ce475516ad New translations strings.xml (Danish) 2024-08-16 03:14:32 +02:00
Eugen Rochko
fb0f15b844 New translations short_description.txt (Danish) 2024-08-16 00:49:38 +02:00
Eugen Rochko
3ca9d7b792 New translations strings.xml (Danish) 2024-08-16 00:49:37 +02:00
Eugen Rochko
a8732fcd20 New translations full_description.txt (Danish) 2024-08-16 00:49:36 +02:00
Eugen Rochko
e7530993a8 New translations full_description.txt (Danish) 2024-08-15 23:54:18 +02:00
Eugen Rochko
fa319023f6 New translations strings.xml (Russian) 2024-08-15 22:48:23 +02:00
Eugen Rochko
84a2585c63 New translations strings.xml (Armenian) 2024-08-15 22:48:22 +02:00
Eugen Rochko
a18fc769bb New translations short_description.txt (Slovak) 2024-08-15 21:28:01 +02:00
Eugen Rochko
b3a4572f6d New translations full_description.txt (Slovak) 2024-08-15 21:28:00 +02:00
Eugen Rochko
12d0ce8ff0 New translations strings.xml (Slovak) 2024-08-15 21:27:59 +02:00
Eugen Rochko
d21ca7c203 New translations strings.xml (Armenian) 2024-08-15 21:27:58 +02:00
Eugen Rochko
075780fe3f New translations full_description.txt (Basque) 2024-08-12 14:08:21 +02:00
Eugen Rochko
223b506284 New translations strings.xml (Basque) 2024-08-12 14:08:20 +02:00
Eugen Rochko
a4dda389c7 New translations strings.xml (Czech) 2024-08-10 18:18:50 +02:00
Eugen Rochko
6e2eaf10fa New translations strings.xml (Thai) 2024-08-09 18:48:08 +02:00
Eugen Rochko
73230643fc New translations strings.xml (Chinese Simplified) 2024-08-07 08:01:50 +02:00
Eugen Rochko
e70cebe2b8 New translations strings.xml (Interlingua) 2024-08-07 00:09:10 +02:00
Eugen Rochko
84e4a750bf New translations strings.xml (Icelandic) 2024-08-05 18:39:51 +02:00
Eugen Rochko
df36166a9e New translations full_description.txt (German) 2024-08-05 04:45:19 +02:00
Eugen Rochko
bb7831483a New translations strings.xml (German) 2024-08-05 04:45:18 +02:00
Eugen Rochko
87f96e6259 New translations strings.xml (Lithuanian) 2024-08-04 19:49:21 +01:00
Eugen Rochko
0db409eb97 New translations strings.xml (Vietnamese) 2024-08-03 17:29:31 +01:00
Eugen Rochko
b4b1f2cade New translations short_description.txt (Portuguese, Brazilian) 2024-08-03 04:17:08 +01:00
Eugen Rochko
884aa8377a New translations full_description.txt (Portuguese, Brazilian) 2024-08-03 04:17:07 +01:00
Eugen Rochko
7f021bc958 New translations full_description.txt (Portuguese, Brazilian) 2024-08-03 02:30:19 +01:00
Eugen Rochko
f4bab5a12e New translations strings.xml (Portuguese, Brazilian) 2024-08-03 02:30:18 +01:00
Eugen Rochko
2bbe5da955 New translations full_description.txt (Belarusian) 2024-08-03 01:22:11 +01:00
Eugen Rochko
819478854d New translations strings.xml (Belarusian) 2024-08-03 00:03:40 +01:00
Eugen Rochko
a58c17e844 New translations strings.xml (Italian) 2024-08-02 21:28:23 +01:00
Eugen Rochko
bf0b91ca92 New translations full_description.txt (Scottish Gaelic) 2024-08-01 15:59:14 +01:00
Eugen Rochko
ed716794d6 New translations strings.xml (Scottish Gaelic) 2024-08-01 15:59:13 +01:00
Eugen Rochko
a2aabe38ec New translations strings.xml (Chinese Traditional) 2024-07-31 17:12:33 +01:00
Grishka
2c9e92a254 Increase limit on explore -> news 2024-07-31 15:00:55 +03:00
Eugen Rochko
390a28ad0e New translations strings.xml (Scottish Gaelic) 2024-07-31 01:33:10 +02:00
Eugen Rochko
2b19135118 New translations strings.xml (Hindi) 2024-07-31 01:33:06 +02:00
Eugen Rochko
3bca29aee2 New translations strings.xml (Thai) 2024-07-31 01:33:05 +02:00
Eugen Rochko
a9cd8954d1 New translations strings.xml (Indonesian) 2024-07-31 01:33:03 +02:00
Eugen Rochko
d9bbd3b243 New translations strings.xml (Portuguese, Brazilian) 2024-07-31 01:33:02 +02:00
Eugen Rochko
0670ac53dc New translations strings.xml (Galician) 2024-07-31 01:33:01 +02:00
Eugen Rochko
f41972bda7 New translations strings.xml (Vietnamese) 2024-07-31 01:33:00 +02:00
Eugen Rochko
994360e52d New translations strings.xml (Chinese Traditional) 2024-07-31 01:32:58 +02:00
Eugen Rochko
a27ae00a5b New translations strings.xml (Turkish) 2024-07-31 01:32:57 +02:00
Eugen Rochko
84d6f162ae New translations strings.xml (Swedish) 2024-07-31 01:32:56 +02:00
Eugen Rochko
031a4e1d28 New translations strings.xml (Slovenian) 2024-07-31 01:32:55 +02:00
Eugen Rochko
934a35b1d3 New translations strings.xml (Russian) 2024-07-31 01:32:54 +02:00
Eugen Rochko
b4b60cee32 New translations strings.xml (Polish) 2024-07-31 01:32:52 +02:00
Eugen Rochko
0a887528ac New translations strings.xml (Norwegian) 2024-07-31 01:32:51 +02:00
Eugen Rochko
c2e5888d7a New translations strings.xml (Dutch) 2024-07-31 01:32:50 +02:00
Eugen Rochko
b51fcfea84 New translations strings.xml (Japanese) 2024-07-31 01:32:47 +02:00
Eugen Rochko
751f0a2726 New translations strings.xml (Italian) 2024-07-31 01:32:46 +02:00
Eugen Rochko
9880a26636 New translations strings.xml (Armenian) 2024-07-31 01:32:44 +02:00
Eugen Rochko
0398dfd1c1 New translations strings.xml (Hungarian) 2024-07-31 01:32:43 +02:00
Eugen Rochko
69cc090a2b New translations strings.xml (Finnish) 2024-07-31 01:32:41 +02:00
Eugen Rochko
9d4df68f02 New translations strings.xml (Danish) 2024-07-31 01:32:40 +02:00
Eugen Rochko
cf621930a8 New translations strings.xml (Czech) 2024-07-31 01:32:38 +02:00
Eugen Rochko
150f7c7137 New translations strings.xml (Catalan) 2024-07-31 01:32:37 +02:00
Eugen Rochko
b4a7828e6d New translations strings.xml (Arabic) 2024-07-31 01:32:36 +02:00
Eugen Rochko
8226e57597 New translations strings.xml (Spanish) 2024-07-31 01:32:35 +02:00
Eugen Rochko
97d52b625a New translations strings.xml (French) 2024-07-31 01:32:34 +02:00
Eugen Rochko
33d0cfd89c New translations strings.xml (Interlingua) 2024-07-31 01:32:32 +02:00
Eugen Rochko
585100f2a0 New translations strings.xml (Persian) 2024-07-31 01:32:31 +02:00
Eugen Rochko
87485beddc New translations strings.xml (Icelandic) 2024-07-31 01:32:30 +02:00
Eugen Rochko
da44b45af5 New translations strings.xml (Chinese Simplified) 2024-07-31 01:32:29 +02:00
Eugen Rochko
884bf2e9b4 New translations strings.xml (Basque) 2024-07-31 01:32:28 +02:00
Eugen Rochko
6efa929e21 New translations strings.xml (Greek) 2024-07-31 01:32:27 +02:00
Eugen Rochko
9f497724f5 New translations strings.xml (German) 2024-07-31 01:32:26 +02:00
Eugen Rochko
21b55c18fb New translations strings.xml (Belarusian) 2024-07-31 01:32:24 +02:00
Eugen Rochko
7d846d7862 New translations strings.xml (Ukrainian) 2024-07-31 01:32:23 +02:00
Eugen Rochko
67496023f7 New translations strings.xml (Lithuanian) 2024-07-31 01:32:22 +02:00
Grishka
30fcb19f9b AND-156 2024-07-31 02:20:43 +03:00
Eugen Rochko
506aa36017 New translations full_description.txt (Italian) 2024-07-31 00:29:16 +02:00
Eugen Rochko
0789753c28 New translations full_description.txt (Icelandic) 2024-07-29 20:38:04 +02:00
Eugen Rochko
bfeb230f3f New translations full_description.txt (Thai) 2024-07-29 16:30:46 +02:00
Eugen Rochko
f8e3b295ef New translations full_description.txt (Icelandic) 2024-07-29 16:30:44 +02:00
Eugen Rochko
0dbe21cb9c New translations strings.xml (German) 2024-07-29 16:30:42 +02:00
Eugen Rochko
4fc36693be New translations full_description.txt (Thai) 2024-07-29 14:23:40 +02:00
Eugen Rochko
fa3366141e New translations strings.xml (Chinese Simplified) 2024-07-29 08:12:30 +02:00
Eugen Rochko
5583948e73 New translations full_description.txt (Interlingua) 2024-07-28 14:32:39 +02:00
Eugen Rochko
a71fccecec New translations strings.xml (Interlingua) 2024-07-28 14:32:38 +02:00
Eugen Rochko
47a70dd648 New translations full_description.txt (Japanese) 2024-07-27 07:40:38 +02:00
Eugen Rochko
3507043494 New translations short_description.txt (Ukrainian) 2024-07-26 17:43:39 +02:00
Eugen Rochko
827185b394 New translations full_description.txt (Ukrainian) 2024-07-26 17:43:38 +02:00
Eugen Rochko
1173e0d44a New translations full_description.txt (Ukrainian) 2024-07-26 16:42:18 +02:00
Eugen Rochko
cca0428f35 New translations strings.xml (Ukrainian) 2024-07-26 16:42:17 +02:00
Eugen Rochko
bfe3c0316c New translations strings.xml (Persian) 2024-07-26 14:33:25 +02:00
Eugen Rochko
2e3a035109 New translations full_description.txt (Chinese Simplified) 2024-07-26 11:45:57 +02:00
Eugen Rochko
8ed73e0f03 New translations strings.xml (Chinese Simplified) 2024-07-26 11:45:56 +02:00
Eugen Rochko
3479618077 New translations full_description.txt (Chinese Simplified) 2024-07-26 10:39:52 +02:00
Eugen Rochko
a429a90ce5 New translations strings.xml (Chinese Simplified) 2024-07-26 10:39:51 +02:00
Eugen Rochko
7c4d8577a6 New translations short_description.txt (Chinese Simplified) 2024-07-26 06:50:37 +02:00
Eugen Rochko
d5bdb1afdb New translations full_description.txt (Chinese Simplified) 2024-07-26 06:50:36 +02:00
Eugen Rochko
e4504e3d54 New translations strings.xml (Chinese Simplified) 2024-07-26 05:31:57 +02:00
Eugen Rochko
e679b17aa7 New translations full_description.txt (Basque) 2024-07-26 03:34:41 +02:00
Eugen Rochko
19b5586e09 New translations strings.xml (Basque) 2024-07-26 03:34:40 +02:00
Eugen Rochko
3b3158bc68 New translations short_description.txt (Basque) 2024-07-26 02:32:36 +02:00
Eugen Rochko
15d21f4eb5 New translations full_description.txt (Basque) 2024-07-26 02:32:36 +02:00
Eugen Rochko
c76c27684f New translations strings.xml (Basque) 2024-07-26 02:32:35 +02:00
Eugen Rochko
77c5dbf7f5 New translations full_description.txt (Japanese) 2024-07-25 18:12:25 +02:00
Eugen Rochko
0e5fd46254 New translations full_description.txt (Japanese) 2024-07-25 16:27:40 +02:00
Eugen Rochko
db69fd76f4 New translations full_description.txt (Japanese) 2024-07-25 15:19:14 +02:00
Eugen Rochko
3723b275c6 New translations short_description.txt (Japanese) 2024-07-25 08:14:41 +02:00
Eugen Rochko
07d7e2ff10 New translations full_description.txt (Japanese) 2024-07-25 08:14:40 +02:00
Eugen Rochko
cac52e13f6 New translations full_description.txt (Icelandic) 2024-07-24 21:12:32 +02:00
Eugen Rochko
169a84ad93 New translations strings.xml (Lithuanian) 2024-07-23 23:58:41 +02:00
Eugen Rochko
b16da68f7b New translations full_description.txt (Italian) 2024-07-23 02:08:46 +02:00
Eugen Rochko
84b241e27e New translations full_description.txt (Japanese) 2024-07-22 09:20:18 +02:00
Eugen Rochko
22041e43ed New translations full_description.txt (Japanese) 2024-07-22 02:55:05 +02:00
Eugen Rochko
75a1ff5eb7 New translations full_description.txt (Japanese) 2024-07-22 01:48:10 +02:00
Adil Lari
4b831d1ba0 Add margins to center icons *together* 2024-07-21 18:23:27 -05:00
Eugen Rochko
b326acb018 New translations full_description.txt (Dutch) 2024-07-21 19:40:52 +02:00
Eugen Rochko
160ed459e6 New translations full_description.txt (Dutch) 2024-07-21 18:29:19 +02:00
Eugen Rochko
13c51ba464 New translations short_description.txt (Dutch) 2024-07-21 17:16:04 +02:00
Eugen Rochko
99b78659ec New translations short_description.txt (Icelandic) 2024-07-21 14:52:01 +02:00
Eugen Rochko
9d5965725e New translations full_description.txt (Icelandic) 2024-07-21 14:52:00 +02:00
Eugen Rochko
e89fc80ca1 New translations strings.xml (Greek) 2024-07-21 14:51:59 +02:00
Eugen Rochko
70e9fcbc72 New translations strings.xml (Lithuanian) 2024-07-21 14:51:58 +02:00
Eugen Rochko
f4412fdec1 New translations strings.xml (Greek) 2024-07-21 12:40:04 +02:00
Gregory K
1d25494274 Merge pull request #866 from nikclayton/patch-1
fix: Remove charset from application/json content type
2024-07-20 16:08:48 +03:00
Nik Clayton
74042dee06 fix: Remove charset from application/json content type
Per https://datatracker.ietf.org/doc/html/rfc8259, application/json does not have a charset parameter
2024-07-20 15:01:52 +02:00
Eugen Rochko
0e630d6506 New translations strings.xml (Belarusian) 2024-07-17 14:24:34 +02:00
26302 changed files with 168943 additions and 3544 deletions

107
README.md
View File

@@ -1,26 +1,92 @@
Mastodon for Android
======================
# ![MoshidonLogo](mastodon/src/main/res/mipmap-xhdpi/ic_launcher_round.png) Moshidon, the material you mastodon client!
[![Crowdin](https://badges.crowdin.net/mastodon-for-android/localized.svg)](https://crowdin.com/project/mastodon-for-android)
## This is the rewrite branch. Things probably won't as you expect here for a while
This is the repository for the official Android app for Mastodon.
> A fast, highly customizable, up-to-date fork of [megalodon](https://github.com/sk22/megalodon) adding important features such as a fully federated timeline, unlisted posting, drafts, scheduled posts, bookmarks, and alt text warnings.
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/org.joinmastodon.android/)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png"
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=org.joinmastodon.android)
Or get the APK from the [The Releases Section](https://github.com/mastodon/mastodon-android/releases/latest).
## Download Now
## Contributing
<a href="https://play.google.com/store/apps/details?id=org.joinmastodon.android.moshinda"><img height="35" alt="Get it on Google Play" src="img/google-play-badge.png"></a> <a href="https://f-droid.org/pt_BR/packages/org.joinmastodon.android.moshinda"><img height="35" alt="Get it on F-Droid" src="img/f-droid-badge.png"></a> <a href="https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.moshinda"><img height="35" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
Our goal is delivering a polished, professionally designed and user-friendly app. We proceed according to wireframes provided by a professional UX designer that works with Mastodon gGmbH. This means that any outside contributions that change the app visually must first be coordinated with the UX designer. *This can take time.* Furthermore, we work off of an internal roadmap and aim for feature-parity and consistency with our iOS app. The iOS app is designated as the "primary" between the two, therefore, if you want to request features, please do so in the [Mastodon for iOS](https://github.com/mastodon/mastodon-ios) repository, as you are requesting a feature to be both in iOS and Android (exceptions being system integrations specific to Android). On the other hand, any contributions that improve existing functionality, performance, or accessibility should not have any roadblocks to being merged.
[![GitHub Release Download](https://img.shields.io/badge/dynamic/json?color=282C37&label=Download%20APK&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2FLucasGGamerM%2Fmoshidon%2Freleases%2Flatest&style=for-the-badge)](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk) [![Translation status](https://translate.codeberg.org/widgets/moshidon/-/svg-badge.svg)](https://translate.codeberg.org/engage/moshidon/) [![GitHub Nightly Download](https://img.shields.io/badge/dynamic/json?color=282C37&label=Download%20Nightly%20APK&query=%24.tag_name&url=https%3A%2F%2Fapi.github.com%2Frepos%2FLucasGGamerM%2Fmoshidon%2Freleases%2Flatest&style=for-the-badge)](https://github.com/LucasGGamerM/moshidon-nightly/releases/latest/download/moshidon-nightly.apk) [![GitHub Nightly Build Download](https://github.com/LucasGGamerM/moshidon/actions/workflows/nightly-builds.yml/badge.svg)](https://github.com/LucasGGamerM/moshidon/actions/workflows/nightly-builds.yml)
If you would like to help translate the app into your language, please go to [Crowdin](https://crowdin.com/project/mastodon-for-android). If your language is not listed in the Crowdin project, please create an issue and we will add it. Please do not create pull requests that modify `strings.xml` files for languages other than English.
## Donate
## Building
<a href="https://github.com/sponsors/LucasGGamerM">Github Sponsors</a> | <a href="https://liberapay.com/LucasGGamerM/donate">Liberapay</a> | Monero Wallet Key: `4886mdarcyB6Yf8Qc6vDJBK1fz6ibHFLZUmHb4GZZz9yLGNhcG3XC64e5UZ8dVQYTLZb82W6P9WhteowW4STJEec97Gf22j`
## Key Features
[ screenshot of full timeline in default colour scheme ]
[ screenshot of full timeline in an alt colour scheme ]
[ screenshot of profile page ]
[ screenshot of compose post window ]
### Flexible Timelines
[ Home dropdown menu ]
Under the Home menu by default you can see your active account's timeline, your server's local timeline, and your server's federated timeline. You can also pin hashtags, lists, other servers, or make a custom view of just your posts, your bookmarks, or your favourites for quick access. Then sort these timelines to prioritize the ones you visit most often.
### Multiple Accounts & Crossposting
Sign in to multiple accounts in the same app and easily switch between them. Press and hold on the boost or fave button to boost or fave a post to a different account than the one you are currently browsing with.
[ boost icon pop up select profile ]
### Drafts & Scheduled Posts
Write posts and save them, or schedule them to post later. Edit and delete your drafts.
### Alt Text Tag & Reminder
An unobtrusive ALT tag appears on images with alt text. Clicking on the icon makes the alt text appear. By default, Moshidon will show a warning to add alt text if your post has any attachments lacking alt text. This is for better accessibility, and it can be disabled in settings. You can also hide from your feed all posts that are lacking in alt text.
[ image with alt text icon higlighted ]
[ alt text expanded ]
### Themes & Customization
Moshidon is designed according to Material Design principles. Follow your device's light or dark mode settings or change colour palette - your system's default, purple, black & white, "pitch black" (battery saving) and more. Customize your experience by moving or renaming the publish button, show or hide sensitive media by default, reduce motion, collapse long posts, add haptic feedback, or making the fave button a heart &hearts; or a star &starf;.
### Not Just For Mastodon
Supports features available on other types of fediverse servers such as admin announcements, showing pronouns in user names, post translation, emoji reactions, local-only posting, and markdown or html in posts.
### Fully Federated Feed & Profiles
See all public posts from servers your server federates with and fetch profiles from a user's local server for accurate up to date information.
## And more...
- quote-posts - links to fediverse posts in other posts will be loaded inline like quote-tweets
- manage pinned posts and bookmarks
- manage lists, filters, and most privacy settings
- display pronouns in timelines, threads, and user listings
- get only specific types of notifications (no more finished polls!), limit who you get notifications from, or group all notifications into one.
- automatically add "re:" to beginning of replies with content warnings
- ask before boosting or deleting posts
- when replying to a boosted post automatically mention the person who boosted it
- overlay audio from posts, allowing your existing media to keep playing
- auto-reveal CWs that are the same as ones you've already opened, or always reveal content warnings and sensitive media
- hide media previews in timelines (save data)
- show post interaction counts in timeline
- allow custom emoji in display names
- enable scrolling text for long display names
- hide interaction buttons
- show post dividers
## Installation & Releases
Moshidon is available on GitHub, Google Play, F-Droid, and the IzzyOnDroid repo. All sources provide the same ` moshidon.apk ` stable release. Older releases are available on the [Releases](https://github.com/LucasGGamerM/moshidon/releases) page.
### How to Install from GitHub
[Download the latest stable release from Github](https://github.com/LucasGGamerM/moshidon/releases/latest/download/moshidon.apk) and open it. You might have to accept installing APK files from your browser. Moshidon will automatically check for new updates available on GitHub and offer to download and install them within the app. You can also manually press “Check for updates” at the bottom of the settings page.
### Nightly Version
All ` moshidon-night.apk ` nightly builds can be downloaded on the [Nightly Releases](https://github.com/LucasGGamerM/moshidon-nightly/releases) page. This is an unstable version with an integrated updater for development and testing purposes. If you find any bugs with it, please file a bug report on our [Issues](https://github.com/LucasGGamerM/moshidon/issues) page.
## Building & Contributing
As this app is using Java 17 features, you need JDK 17 or newer to build it. Other than that, everything is pretty standard. You can either import the project into Android Studio and build it from there, or run the following command in the project directory:
@@ -32,4 +98,13 @@ As this app is using Java 17 features, you need JDK 17 or newer to build it. Oth
This project is released under the [GPL-3 License](./LICENSE).
The Mastodon name and logo are trademarks of Mastodon gGmbH. If you intend to redistribute a modified version of this app, use a unique name and icon for your app that does not mistakenly imply any official connection with or endorsement by Mastodon gGmbH.
## Contact & Support
**<a rel="me" href="https://floss.social/@moshidon">@moshidon@floss.social</a>**
[Official Matrix Chatroom](https://matrix.to/#/#moshidon:floss.social)
[F.A.Q](FAQ.md)
[Moshidon Roadmap](https://github.com/users/LucasGGamerM/projects/1)

View File

@@ -28,7 +28,7 @@ platform :android do
build_type: "release",
)
upload_to_play_store(
changes_not_sent_for_review: true,
release_status: "draft",
skip_upload_images: true,
skip_upload_screenshots: true
)

View File

@@ -2,60 +2,60 @@ Mastodon - лепшы спосаб быць у курсе ўсяго, што а
Гэта афіцыйная праграма для Android ад Mastodon. Ён вокамгненна хуткі і прыгожы, распрацаваны, каб быць не толькі функцыянальным, але і простым у выкарыстанні. У нашай праграме вы можаце:
АГЛЕДЗЕЦЬ
ДАСЛЕДАВАЦЬ
■ Адкрыйце для сябе новых пісьменнікаў, журналістаў, мастакоў, фатографаў, навукоўцаў і многае іншае
■ Даведайцеся, што адбываецца ў свеце
READ
ЧЫТАЦЬ
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
Сачыце за людзьмі, якія вам цікавыя, у храналагічнай стужцы без перапыненняў
Сачыце за хэштэгамі, каб быць у курсе канкрэтных тэм у рэжыме рэальнага часу
CREATE
СТВАРАЙЦЕ
Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
Адпраўце паведамленне сваім падпісчыкам ці ўсім свеце, выкарыстоўваючы апытанні, высакаякасныя відарысы і відэа
Удзельнічайце ў цікавых гутарках з іншымі людзьмі
CURATE
КУРЫРУЙЦЕ
Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
Стварайце спісы людзей, каб не прапусціць ні аднаго допісу
Фільтруйце словы і фразы, каб кантраляваць тое, што вы хочаце і не хочаце бачыць
AND MORE!
І БОЛЬШ!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
Прыгожая тэма, якая адаптуецца да вашай індывідуальнай каляровай схемы, светлай ці цёмнай
Абагульвайце і сканіруйце QR-коды, каб хутка абменьвацца профілямі Mastodon з іншымі
Уваход і пераключэнне паміж некалькімі ўліковымі запісамі
Атрымлівайце апавяшчэнне, калі хтосьці публікуе допіс з дапамогай кнопкі званочка
Без спойлераў! Вы можаце размясціць свае допісы за папярэджаннямі аб змесце
A POWERFUL PUBLISHING PLATFORM
МАГУТНАЯ ПУБЛІКАЦЫЙНАЯ ПЛАТФОРМА
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Вам больш не трэба спрабаваць супакоіць непразрысты алгарытм, які вырашае, ці ўбачаць вашы сябры тое, што вы апублікавалі. Калі яны пойдуць за вамі, яны гэта ўбачаць.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Калі вы публікуеце яго ў адкрытым Інтэрнэце, ён становіцца даступным у адкрытым Інтэрнэце. Вы можаце смела дзяліцца спасылкамі на Mastodon, ведаючы, што кожны зможа прачытаць іх без уваходу ў сістэму.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
Акрамя стужак, апытанняў, высакаякасных відарысаў, відэа, аўдыя і папярэджанняў аб змесце, Mastodon прапануе мноства спосабаў выказаць сябе так, як вам зручна.
A POWERFUL READING PLATFORM
МАГУТНАЯ ПЛАТФОРМА ДЛЯ ЧЫТАННЯ
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Нам не трэба паказваць вам рэкламу, таму нам не трэба трымаць вас у нашай праграме. Mastodon мае найбагацейшы выбар старонніх праграм і інтэграцый, так што вы можаце выбраць тое, што вам больш за ўсё падыходзіць.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Дзякуючы храналагічнай хатняй стужцы лёгка вызначыць, калі вы прагледзелі ўсе абнаўленні і можаце перайсці да чагосьці іншага.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
Не трэба турбавацца аб тым, што няправільны клік сапсуе вашы рэкамендацыі назаўжды. Мы не адгадваем, што вы хочаце бачыць, мы дазваляем вам кіраваць гэтым.
PROTOCOLS, NOT PLATFORMS
ПРАТАКОЛЫ, А НЕ ПЛАТФОРМЫ
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
У адрозненне ад традыцыйнай платформы сацыяльных сетак, Mastodon пабудаваны на дэцэнтралізаваным пратаколе. Вы можаце зарэгістравацца на нашым афіцыйным серверы або выбраць трэцюю асобу для размяшчэння вашых даных і мадэрацыі вашага вопыту.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
З агульным пратаколам, незалежна ад таго, што вы абралі, вы можаце бесперашкодна мець зносіны з людзьмі на іншых серверах Mastodon. Але ёсць і больш: толькі з адным уліковым запісам вы можаце размаўляць з людзьмі з іншых платформаў fediverse.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Не задаволены сваім выбарам? Вы заўсёды можаце пераключыцца на іншы сервер Mastodon, узяўшы з сабой падпісчыкаў. Для прасунутых карыстальнікаў вы нават можаце размясціць свае даныя ў сваёй інфраструктуры, паколькі Mastodon з'яўляецца адкрытым зыходным кодам.
NON-PROFIT IN NATURE
НЕКАМЕРЦЫЙНЫ ХАРАКТАРАТ
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon з'яўляецца зарэгістраванай некамерцыйнай арганізацыяй у ЗША і Германіі. Нас матывуе не здабыванне грашовай каштоўнасці з платформы, а тое, што лепш для платформы.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
РЭКАМЕНТАВАНЫЯ Ў: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com і інш.

View File

@@ -0,0 +1,61 @@
Mastodon yw'r ffordd orau o gadw i fyny â'r hyn sy'n digwydd. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
DARGANFOD
■ Discover new writers, journalists, artists, photographers, scientists and more
■ See whats happening in the world
DARLLEN
■ Keep up with people you care about in a chronological feed with no interruptions
■ Follow hashtags to keep up with specific topics in real time
CREU
■ Post to your followers or the whole world, with polls, high quality images and videos
■ Participate in interesting conversations with other people
CURADU
■ Create lists of people to never miss a post
■ Filter words or phrases to control what you do and dont want to see
A MWY!
■ A beautiful theme that adapts to your personalized color scheme, light or dark
■ Share and scan QR codes to quickly exchange Mastodon profiles with others
■ Login and switch between multiple accounts
■ Get notified when a specific person posts with the bell button
■ No spoilers! You can put your posts behind content warnings
A POWERFUL PUBLISHING PLATFORM
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
A POWERFUL READING PLATFORM
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
PROTOCOLAU, NID PLATFFORMAU
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
NID-ER-ELW
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
FEL Y GWELWYD YN: Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, a mwy.

View File

@@ -0,0 +1 @@
Lle mae sgyrsiau yn digwydd

View File

@@ -1,61 +1,61 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon er den bedste måde at holde sig ajour med, hvad der sker. Følg enhver på tværs af fediverset og se alt i kronologisk rækkefølge. Ingen algoritmer, annoncer eller clickbait i syne.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Dette er den officielle Android-app til Mastodon. Den er lynhurtigt og forbløffende smuk, designet til at være ikke blot kraftfuld, men også nem at bruge. I vores app kan man:
EXPLORE
UDFORSKE
■ Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
● Opdag nye forfattere, journalister, kunstnere, fotografer, forskere med mere
Se, hvad der sker i verden
READ
LÆSE
■ Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
● Bliv holdt ajour med folk, man holder af, i et kronologisk feed uden afbrydelser
Følg hashtags for at være i tråd med bestemte emner i realtid
CREATE
OPRETTE
Post to your followers or the whole world, with polls, high quality images and videos
■ Participate in interesting conversations with other people
Post til følgere eller hele verden, med meningsmålinger, højkvalitets billeder og videoer
● Deltag i interessante samtaler med andre mennesker
CURATE
KURATERE
■ Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
● Opret lister over personer for aldrig at gå glip af et indlæg
Filtr ord eller sætninger for at styre, hvad man ønsker, og ikke ønsker, at se
AND MORE!
OG MERE!
■ A beautiful theme that adapts to your personalized color scheme, light or dark
■ Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
■ Get notified when a specific person posts with the bell button
■ No spoilers! You can put your posts behind content warnings
● Et smukt tema, der tilpasser sig den personlige farvesammensætning, lys eller mørk
● Del og skan QR-koder for hurtigt at udveksle Mastodon-profiler med andre
Log ind og skift mellem flere konti
● Få besked med klokkeknappen, når en bestemt person poster
● Ingen spoilers! Man kan placere sine indlæg bag indholdsadvarsler
A POWERFUL PUBLISHING PLATFORM
EN KRAFTFULD UDGIVELSESPLATFORM
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Man behøver ikke længere at forsøge at formilde en uigennemsigtig algoritme, der beslutter, om vennerne vil se, hvad man har postet. Følges man af dem, vil de se det.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Udgiver man det til det åbne net, er det tilgængeligt på det åbne net. Man kan sikkert dele links via Mastodon med den viden, at alle vil være i stand til at læse dem uden at logge ind.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
Mellem tråde, afstemninger, højkvalitets billeder, videoer, lyd og indholdsadvarsler, tilbyder Mastodon masser af måder at udtrykke sig på en måde, man finder passende.
A POWERFUL READING PLATFORM
EN KRAFTFULD LÆSEPLATFORM
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Vi behøver ikke at vise brugere annoncer, så vi behøver ikke at holde dem i vores app. Mastodon har det rigeste udvalg af 3. parts apps og integrationer, så man kan vælge mest passende oplevelse.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Takket være det kronologiske hjemme-feed er det nemt at vide, når man er i tråd med alle opdateringer og kan gå videre til noget andet.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
Ingen grund til bekymringer over, at man får sine anbefalinger ødelagt for evigt med et fejlklik. Vi gætter ikke, hvad brugerne ønsker at se, vi lader dem styre det.
PROTOCOLS, NOT PLATFORMS
PROTOKOLLER, IKKE PLATFORME
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Mastodon er ikke som en traditionel social medieplatform, men baserer sig på en decentraliseret protokol. Man kan tilmelde sig på vores officielle server, eller vælge en 3. part til at være vært for sine data og moderere ens oplevelse.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Takket være den fælles protokol, kan man, uanset hvad man vælger, kommunikere problemfrit med folk på andre Mastodon-servere. Der er mere endnu: Med kun én konto kan man kommunikere med folk fra andre fediverse-platforme.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Ikke tilfreds med valget? Man kan altid skifte til en anden Mastodon-server, mens man tager sine tilhængere med sig. For avancerede brugere, man kan endda være vært for sine data på sin egen infrastruktur, da Mastodon er open-source.
NON-PROFIT IN NATURE
NON-PROFIT AF NATUR
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon er registreret som non-profit i USA og Tyskland. Vi er ikke motiveret af at udvinde pengeværdi fra platformen, men ved hvad der er bedst for den.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
SOM OMTALT I: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com og flere.

View File

@@ -1 +1 @@
Where conversations happen
Hvor samtaler finder sted

View File

@@ -5,34 +5,34 @@ Das ist die offizielle Android-App für Mastodon. Blitzschnell und atemberaubend
ENTDECKEN
■ Neue Autoren, Journalisten, Künstler, Fotografen, Wissenschaftler und viele andere entdecken
■ See whats happening in the world
■ Sehen Sie, was in der Welt passiert
READ
LESEN
Keep up with people you care about in a chronological feed with no interruptions
■ Follow hashtags to keep up with specific topics in real time
Bleiben Sie in einem chronologischen Feed ohne Unterbrechungen über die Menschen auf dem Laufenden, die Ihnen wichtig sind
■ Folgen Sie Hashtags, um in Echtzeit über bestimmte Themen auf dem Laufenden zu bleiben
KREIEREN
■ Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
■ Posten Sie für Ihre Follower oder die ganze Welt mit Umfragen, hochwertigen Bildern und Videos
Nehmen Sie an interessanten Gesprächen mit anderen Menschen teil
GESTALTEN
Create lists of people to never miss a post
■ Filter words or phrases to control what you do and dont want to see
Erstellen Sie Listen mit Personen, um nie einen Beitrag zu verpassen
■ Filtern Sie Wörter oder Ausdrücke, um zu steuern, was Sie sehen möchten und was nicht
UND MEHR!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
Ein schönes Design, das sich an Ihr persönliches Farbschema anpasst, ob hell oder dunkel
Teilen und scannen Sie QR-Codes, um Mastodon-Profile schnell mit anderen auszutauschen
Anmelden und zwischen mehreren Konten wechseln
Lassen Sie sich benachrichtigen, wenn eine bestimmte Person mit der Klingeltaste postet
■ Keine Spoiler! Du kannst deine Beträge hinter Inhaltswarnungen stellen
EINE MÄCHTIGE PLATTFORM ZUM VERÖFFENTLICHEN
Du musst nicht länger versuchen, einen undurchsichtigen Algorithmus dir wohlgesinnt zu stimmen, der darüber entscheidet, ob deine Freunde sehen, was du postest. If they follow you, theyll see it.
Du musst nicht länger versuchen, einen undurchsichtigen Algorithmus dir wohlgesinnt zu stimmen, der darüber entscheidet, ob deine Freunde sehen, was du postest. Wenn Sie Ihnen folgen, werden Sie es sehen.
Wenn du es im offenen Web veröffentlichst, ist es auch zugänglich im offenen Web. Du kannst ganz unbekümmert Links auf Mastodon teilen in dem Wissen, dass jeder sie ohne Einloggen wird lesen können.

View File

@@ -0,0 +1,4 @@
- We're rolling out grouped notifications for servers that support the feature
- You can now click "show results" on polls without having to submit a vote
- You will now see lines connecting reply chains in threads
- Bug fixes and improvements, obviously!

View File

@@ -0,0 +1,7 @@
- New option to use our color theme instead of Material You
- Support for the color contrast setting in Android 15
- You can now crop your profile picture when editing your profile
- You can now long-press "Add media" in the composer to bring up the file picker
- New look for the media viewer
- New follower notifications will now appear grouped
- Directional loading for gaps in timelines: load newer posts when scrolling up, older when down

View File

@@ -0,0 +1,6 @@
- Settings are now split into global settings and account-specific settings for each account you're logged into
- Profiles now show who of the people you follow also follows this person
- More easily swap between posts, profiles and hashtags when using search
- We now tell you exactly how many followers you'd lose when blocking a whole server so you can avoid costly mistakes
- Bookmarks and favourites have moved to a new tab on your profile
- The button that loads missing posts is now more upfront about which direction it's going to load in

View File

@@ -1 +1 @@
110.txt
128.txt

View File

@@ -1,61 +1,61 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon gertatzen ari denari buruz egunean egoteko modurik onena da. Jarraitu edonor fedibertsoan eta ikusi dena ordena kronologikoan. Ez dago algoritmorik, iragarkirik edo clickbait-ik bistan.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Hau Android gailuentzako Mastodon aplikazio ofiziala da. Ikaragarri azkarra eta ikaragarri ederra da, ahaltsua ez ezik, erabilerraza ere izateko diseinatua. Gure aplikazioan, hauek egin ditzakezu:
EXPLORE
ESPLORATU
Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
Ezagutu idazle, kazetari, artista, argazkilari, zientzialari eta gehiago
Ikusi zer ari den gertatzen munduan
READ
IRAKURRI
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
Axola zaizkizun pertsonei buruz egunean egotea, etenik gabeko horma kronologikoarekin
Jarraitu hashtag-ak gai espezifikoekin denbora errealean informatuta egoteko
CREATE
SORTU
Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
Bidali bidalketak zure jarraitzaileei edo mundu guztiari, inkestekin, kalitate handiko irudiekin eta bideoekin
Beste pertsona batzuekin elkarrizketa interesgarrietan parte hartu
CURATE
ONDU
Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
Pertsonen zerrendak sortu elkarrizketa bat inoiz ez galtzeko
Hitzak edo esaldiak iragazi ikusi nahi duzuna eta ikusi nahi ez duzuna kontrolatzeko
AND MORE!
ETA GEHIAGO!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
Zure kolore eskema pertsonalizatura egokitzen den gai ederra, argia edo iluna
Partekatu eta eskaneatu QR kodeak Mastodon profilak beste batzuekin azkar trukatzeko
Saioa hasi eta aldatu hainbat konturen artean
Jakinarazpenak jaso pertsona jakin batek argitaratzen duenean kanpaiaren botoiarekin
Izorrakirik ez! Zure mezuak eduki abisuekin babes ditzakezu
A POWERFUL PUBLISHING PLATFORM
ARGITARATZEKO PLATAFORMA INDARTSUA
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Jada ez duzu algoritmo opako bat baretzen saiatu behar, zure lagunek argitaratu zenuena ikusiko duten ala ez erabakitzen duena. Jarraitzen badizute, ikusiko dute.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Web irekian argitaratzen baduzu, web irekian eskuragarri dago. Mastodonerako loturak segurtasunez parteka ditzakezu, jakinda edozeinek irakurri ahal izango dituela saioa hasi gabe.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
Harien, inkesten, irudien, bideoen, audioaren eta edukien ohartarazpenen artean, Mastodonek modu asko eskaintzen ditu komeni zaizun moduan adierazteko.
A POWERFUL READING PLATFORM
IRAKURTZEKO PLATAFORMA INDARTSUA
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Ez dizugu iragarkirik erakutsi behar; beraz, ez dizugu eutsi behar gure aplikazioan. Mastodonek hirugarrenen aplikazio eta integrazioen aukeraketa aberatsena du, gehien komeni zaizun esperientzia aukera dezazun.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Orri nagusiko jario kronologikoari esker, erraza da jakitea noiz aurkitu dituzun eguneraketa guztiak eta beste gauza batera pasa zaitezke.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
Ez dago kezkatu beharrik okerreko klik batek betiko zure gomendioak hondatuko dituela. Ez dugu asmatzen zer ikusi nahi duzun, zuk kontrola dezazun uzten dugu.
PROTOCOLS, NOT PLATFORMS
PROTOKOLOAK, PLATAFORMARIK EZ
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Mastodon ez da sare sozialen ohiko plataforma bat, protokolo deszentralizatu batean oinarritzen da. Gure zerbitzari ofizialean izena eman dezakezu edo hirugarren bat aukeratu zure datuak ostatatzeko eta zure esperientzia moderatzeko.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Protokolo komunari esker, ez du axola zer aukeratzen duzun, arazorik gabe komunika zaitezke jendearekin beste Mastodon zerbitzari batzuetan badaude ere. Are gehiago: kontu bakar batekin, fedibertsoko beste plataforma batzuetako jendearekin komunika zaitezke.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Ez al zaude pozik zure aukerarekin? Beti alda dezakezu Mastodon zerbitzari desberdin batera zure jarraitzaileak zurekin eramaten dituzun bitartean. Erabiltzaile aurreratuentzat, zure datuak zure azpiegituran bertan ostatatu ditzakezu, Mastodon software librea baita.
NON-PROFIT IN NATURE
IRABAZI ASMORIK GABE IZAERAZ
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon Estatu Batuetan eta Alemanian erregistratutako irabazi-asmorik gabeko erakundea da. Ez gaude motibatuta plataformaren diru-balioa ateratzeagatik, baizik eta plataformarentzat hobea denagatik.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
HEMEN AGERTZEN DEN BEZALA: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo PCMAG.com, eta gehiago.

View File

@@ -1 +1 @@
Where conversations happen
Elkarrizketak gertatzen diren lekua

View File

@@ -1,61 +1,61 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
ماستودون بهترین راه برای پیگیری اتفاقات است. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
این کاره رسمی اندروید برای ماستودون است. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. در کاره ما، شما می‌توانید:
EXPLORE
گشت و گذار
■ Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
ببینید در دنیا چه رخ می‌دهد
READ
خواندن
■ Keep up with people you care about in a chronological feed with no interruptions
■ Follow hashtags to keep up with specific topics in real time
CREATE
ایجاد کردن
■ Post to your followers or the whole world, with polls, high quality images and videos
■ Participate in interesting conversations with other people
CURATE
Create lists of people to never miss a post
سیاهه‌ای از افراد ایجاد کنید تا هرگز فرسته‌ای را از دست ندهید
■ Filter words or phrases to control what you do and dont want to see
AND MORE!
و بیشتر!
■ A beautiful theme that adapts to your personalized color scheme, light or dark
■ Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
وارد شوید و بین چند حساب جابجا شوید
■ Get notified when a specific person posts with the bell button
■ No spoilers! You can put your posts behind content warnings
A POWERFUL PUBLISHING PLATFORM
یک سکوی انتشار قدرتمند
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. اگر آنها شما را پی بگیرند، آن را خواهند دید.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
A POWERFUL READING PLATFORM
یک سکوی خواندن قدرتمند
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
ما نیازی به نمایش تبلیغات به شما نداریم، بنابراین لازم نیست شما را در کاره‌مان نگه داریم. ماستودون غنی‌ترین مجموعه از برنامه‌ها و ادغام‌های شخص ثالث را دارد، بنابراین می‌توانید تجربه‌ای را انتخاب کنید که مناسب شما است.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
به لطف خوراک زمانی خانه، تشخیص اینکه چه زمانی از همه به‌روزرسانی‌ها مطلع شده‌اید و می‌توانید به چیز دیگری بروید، آسان است.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
لازم نیست نگران باشید که یک کلیک اشتباه توصیه های شما را برای همیشه خراب می کند. ما حدس نمی‌زنیم که چه چیزی می‌خواهید ببینید، به شما اجازه می‌دهیم آن را کنترل کنید.
PROTOCOLS, NOT PLATFORMS
شیوه‌نامه‌ها، بدون سکوها
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
به لطف پروتکل مشترک، مهم نیست که چه چیزی را انتخاب می کنید، می‌توانید به طور یکپارچه با افراد در سایر کارسازهای ماستودون ارتباط برقرار کنید. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
از انتخاب خود خوشحال نیستید؟ You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
NON-PROFIT IN NATURE
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
ماستودون یک سازمان غیرانتفاعی ثبت شده در ایالات متحده و آلمان است. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.

View File

@@ -1 +1 @@
Where conversations happen
کجا گفتگوها اتفاق می‌افتد

View File

@@ -1,44 +1,44 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon est le meilleur endroit pour se tenir au courant de ce qui se passe. Suivez n'importe qui à travers le fédivers et découvrez tout dans un ordre chronologique. Pas d'algorithmes, de publicités ou de pièges à clics dans le coin.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Ceci est l'application Android officielle de Mastodon. Elle est extrêmement rapide et d'une beauté époustouflante, conçue pour être non seulement puissante, mais aussi facile d'utilisation. Dans notre application, vous pouvez :
EXPLORE
EXPLORER
■ Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
■ Découvrir de nouveaux et nouvelles écrivain·e·s, journalistes, artistes, photographes, scientifiques et plus encore
Voir ce qui se passe dans le monde
READ
LIRE
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
Suivez les gens qui vous intéressent dans un flux chronologique sans interruption
Suivez les hashtags pour suivre des sujets spécifiques en temps réel
CREATE
CRÉER
■ Post to your followers or the whole world, with polls, high quality images and videos
■ Participate in interesting conversations with other people
■ Participer à des conversations intéressantes avec d'autres personnes
CURATE
ACTUALISER
■ Create lists of people to never miss a post
■ Filter words or phrases to control what you do and dont want to see
■ Créez des listes de personnes pour ne jamais manquer un post
■ Filtrez les mots ou les phrases pour contrôler ce que vous voulez et ne voulez pas voir
AND MORE!
ET PLUS !
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Un beau thème qui sadapte à vos couleurs personnalisées, claires ou sombres
Partagez et numérisez des codes QR pour échanger rapidement des profils Mastodon avec d'autres personnes
Connexion et bascule entre plusieurs comptes
■ Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
Pas de spoilers ! Vous pouvez mettre vos messages derrière des avertissements de contenu
A POWERFUL PUBLISHING PLATFORM
UNE PUISSANTE PLATEFORME DE PUBLICATION
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Vous n'avez plus à dépendre d'un algorithme opaque qui décide si vos amis vont voir ce que vous avez posté. S'ils vous suivent, ils le verront.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
A POWERFUL READING PLATFORM
UNE PUISSANTE PLATEFORME DE LECTURE
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
@@ -46,9 +46,9 @@ Thanks to the chronological home feed, its easy to tell when youve caught
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
PROTOCOLS, NOT PLATFORMS
PROTOCOLS, ET NON PLATEFORMES
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
« Mastodon » n'est pas un média social traditionnel, il est conçu sur la base d'un protocole décentralisé. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
@@ -56,6 +56,6 @@ Not happy with your choice? You can always switch to a different Mastodon server
NON-PROFIT IN NATURE
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon est une organisation à but non lucratif immatriculée aux États-Unis et en Allemagne. Nous ne sommes pas motivés par des considérations monétaires, mais par ce qu'il y a de mieux pour la plateforme.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.

View File

@@ -1 +1 @@
Where conversations happen
Là où les discussions se déroulent

View File

@@ -0,0 +1,61 @@
Mastodon is de beste manier om by te hâlden wat der bart. Folgje elkenien yn de fediverse en sjoch alles yn gronologyske folchoarder. Gjin algoritmen, advertinsjes of clickbait te bekennen.
Dit is de offisjele Android-app foar Mastodon. It is razendfluch en bjusterbaarlik moai. Untwurpen om net allinnich krêftich, mar ek brûkersfreonlik te wêzen. Yn ús app kinne jo:
UNTDEKKE
■ Nije skriuwers, sjoernalisten, keunstners, fotografen, wittenskippers en mear ûntdekke
■ Sjoch wat der yn de wrâld bart
LÊZE
■ Op de hichte bliuwe fan minsken om wat jo jouwe, op in gronologyske tiidline en sûnder ûnderbrekkingen
■ Hashtags yn realtime folgje om op de hichte te bliuwen fan spesifike ûnderwerpen
KREËARJE
■ Berjochten nei allinnich dyn folgers stjoere of nei de hiele wrâld, mei peilingen, ôfbyldingen fan hege kwaliteit en fideos
■ Oan ynteressante petearen mei oare minsken dielnimme
ONTWERPEN
■ Listen meitsje mei minsken dyt jo folgje, om sa nea in berjocht te missen
■ Wurden of sinnen filterje om te bepalen wat jo wol en net sjen wolle
EN MEAR!
■ In prachtich tema dat har oanpast oan jo persoanlike kleureskema, ljocht of donker
■ QR-koaden scanne om gau Mastodon-profilen mei oare minsken te dielen
■ Meardere accounts brûke
■ Meldingen fan spesifike persoanen ûntfange, wanneart dizze berjochten pleatse
■ Gjin spoilers! ■ Jo kinne jo berjochten efter ynhâldswarskôgingen pleatse
IN KRÊFTICH PUBLIKAASJEPLATFOARM
Jo hoege net langer te probearjen in ûntrochsichtich algoritme tefreden te stellen, dat beslist oft jo freonen wol of net sjen meie wat jo pleatst hawwe. As se jo folgje, sille se it sjen.
Wanneart jo it yn de fediverse pleatse, is it ek tagonklik yn de fediverse. Jo kinne feilich keppelingen nei Mastodon diele, yn de wittenskip dat elkenien se lêze kin sûnder oan hoege te melden.
Mei petearen, peilingen, ôfbyldingen fan hege kwaliteit, fideos, audio en ynhâld s warskôgingen, biedt Mastodon genôch manieren om josels uterje te kinnen, op in manier dyt by jo past.
IN KRÊFTICH LÊSPLATFOARM
Wy hoege jo gjin advertinsjes sjen te litten, dus wy hoege jo ek net foar ús app te behâlden. Mastodon hat de rykste kar oan troch tredden ûntwikkele apps en yntegraasjes, sadat jo de brûkersûnderfining kieze kinne dyt it beste by jo past.
Mei tank oan de gronologyske tiidline is it maklik om te sjen wanneart jo alle updates besjoen hawwe en mei wat oars troch gean kinne.
Jo hoege net bang te wêzen dat, wanneart jo op wat ferkeards klikke, jo oanrekommandaasjes foar altyd ferpest binne. We riede net nei wat jo sjen wolle, wy litte it oan jo oer.
PROTOKOLLEN, GJIN PLATFOARMS
Mastodon is net lykas in tradisjoneel sosjaal-mediaplatfoarm, mar is boud op in desintralisearre protool. Jo kinne foar ús offisjele server of foar ien fan in tredde partij kieze om jo gegevens te hosten en brûkers te moderearjen.
Mei tank oan it mienskiplike protokol, kinne jo, likefolle wat jo kieze, naadleas mei minsken op oare Mastodon-servers kommunisearje. Mar der is mear: Mei mar ien account kinne jo mei minsken fan oare fediverse-platfoarms kommunisearje.
Net tefreden mei jo kar? Jo kinne altyd nei ien oare Mastodon-server oerstappe en jo folgers meinimme. Betûfte brûkers kinne harren gegevens sels op harren eigen ynfrastruktuer hoste, omdat Mastodon iepen-boarne is.
NON-PROFIT FAN AARD
Mastodon is in registrearre non-profitorganisaasje yn de Ferienige Steaten en Dútslân. Wy helje ús motivaasje net út it kommersjeel misbrûk meitsje fan Mastodon, mar út wat it beste is foar Mastodon.
FERMELD YN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com en mear.

View File

@@ -0,0 +1 @@
Dêrt petearen ûntstean

View File

@@ -1,36 +1,36 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Is Mastodon an dòigh as fheàrr airson sùil a chumail air na tha a dol. Lean duine sam bith air a cho-shaoghal agus faic a h-uile càil a-rèir an ama. Chan eil sgeul air algairimean, sanasachd no clickbait.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Seo an aplacaid Android oifigeil airson Mastodon. The e àlainn s cho luath ris a ghaoth, air a dhealbhadh ach am biodh e cumhachdach ach furasta cleachdadh. Seo na nì thu san aplacaid againn:
EXPLORE
RÙRAICH
Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
Lorg sgrìobhadairean, luchd-naidheachd, luchd-ealain, luchd togail dhealbhan, luchd-saidheans is eile
Faic na tha a dol air an t-saoghal
READ
LEUGH
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
Gabh naidheachdan na feadhainn a tha cudromach dhut a-rèir an ama s gun bhuairidhean
Lean tagaichean hais airson ceum a chumail ri cuspairean àraid ann am fìor-àm
CREATE
CRUTHAICH
■ Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
■ Postaich chun luchd-leantainn agad no chun t-saoghail air fad, le cunntasan-bheachd agus dealbhan s videothan le càileachd àrd
Gabh pàirt ann an còmhraidhean inntinneach le daoine eile
CURATE
CURAIDICH
■ Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
■ Cruthaich liostaichean de dhaoine ach nach caill thu post uapa-san
Criathraich faclan no abairtean a stiùireadh na chì s nach fhaic thu
AND MORE!
AGUS MÒRAN A BHARRACHD!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
Ùrlar àlainn a fhreagras dhan sgeama dhathan phearsanaichte agad, soilleir no dorcha
Co-roinn is sganaich còdaichean QR airson pròifilean Mhastodon iomlaid le càch sa bhad
Clàraich a-steach s geàrr leum eadar iomadh cunntas
Faigh brath nuair a phostaich cuideigin sònraichte rud le putan a chluig
Gun spoilers! S urrainn dhut na postaichean agad a chur air cùlaibh rabhaidhean susbainte
A POWERFUL PUBLISHING PLATFORM
ÙRLAR FOILLSEACHAIDH CUMHACHDACH
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.

View File

@@ -0,0 +1,61 @@
Mastodon es le melior maniera de sequer lo que passa. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Iste es le app official de Mastodon pro Android. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In nostre app, tu pote:
EXPLORAR
■ Discover new writers, journalists, artists, photographers, scientists and more
■ See whats happening in the world
LEGER
■ Keep up with people you care about in a chronological feed with no interruptions
■ Follow hashtags to keep up with specific topics in real time
CREAR
■ Post to your followers or the whole world, with polls, high quality images and videos
■ Participate in interesting conversations with other people
CURATE
■ Create lists of people to never miss a post
■ Filter words or phrases to control what you do and dont want to see
AND MORE!
■ A beautiful theme that adapts to your personalized color scheme, light or dark
■ Share and scan QR codes to quickly exchange Mastodon profiles with others
■ Login and switch between multiple accounts
■ Get notified when a specific person posts with the bell button
■ No spoilers! You can put your posts behind content warnings
A POWERFUL PUBLISHING PLATFORM
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
A POWERFUL READING PLATFORM
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
PROTOCOLS, NOT PLATFORMS
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
NON-PROFIT IN NATURE
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.

View File

@@ -1,61 +1,61 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon merupakan cara terbaik untuk tetap mengikuti apa yang terjadi. Ikuti siapapun dalam fediverse dan lihat semuanya secara kronologis. Tidak ada algoritma, iklan, atau clickbait.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Ini adalah aplikasi Android resmi untuk Mastodon. Cepat dan mengesankan, didesain tidak hanya sekadar kuat tetapi juga mudah digunakan. Di dalam aplikasi ini, anda dapat:
EXPLORE
MENJELAJAHI
■ Discover new writers, journalists, artists, photographers, scientists and more
■ See whats happening in the world
Temukan penulis, jurnalis, kreator, fotografer, ilmuwan, dan lainnya
Melihat apa yang sedang terjadi
READ
MEMBACA
■ Keep up with people you care about in a chronological feed with no interruptions
■ Follow hashtags to keep up with specific topics in real time
Tetap berhubungan dengan orang terdekat anda tanpa gangguan
Mengikuti tagar untuk tetap terupdate dengan topik-topik baru
CREATE
MEMBUAT
■ Post to your followers or the whole world, with polls, high quality images and videos
■ Participate in interesting conversations with other people
Tautkan konten kepada pengikut anda dengan poll, gambar dan video berkualitas tinggi
Berpartisipasi dalam percakapan yang menarik dengan orang lain
CURATE
MENYUSUN
■ Create lists of people to never miss a post
■ Filter words or phrases to control what you do and dont want to see
Buat daftar orang agar tidak ketinggalan
Saring kata atau frasa untuk mengontrol apa yang anda ingin lihat atau tidak
AND MORE!
DAN BANYAK LAGI!
■ A beautiful theme that adapts to your personalized color scheme, light or dark
■ Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
■ Get notified when a specific person posts with the bell button
■ No spoilers! You can put your posts behind content warnings
Tema indah yang menyesuaikan skema warna perangkat anda, terang atau gelap
Bagikan dan pindai QR code untuk bertukar profil Mastodon dengan cepat
Login dengan lebih dari satu akun
Tetap ternotifikasi dengan postingan orang tertentu menggunakan tombol dering
Tidak ada spoilers! Anda bisa mencantumkan postingan anda dibelakang tanda peringatan
A POWERFUL PUBLISHING PLATFORM
PLATFORM PUBLIKASI YANG KUAT
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Anda tidak lagi perlu mengikuti algoritma yang menentukan jika teman anda akan melihat apa yang anda tautkan. Jika mereka mengikuti anda, mereka akan melihat tautan tersebut.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Jika anda mempublikasikan di internet, tautan tersebut dapat diakses di internet. Anda bisa dengan aman membagikan situs di Mastodon dengan catatan bahwa siapa saja dapat melihatnya tanpa login.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
Selain threads, polls, gambar berkualitas tinggi, video, audio, dan peringatan konten, Mastodon menawarkan beragam cara untuk mengekspresikan diri anda dengan cara yang anda inginkan.
A POWERFUL READING PLATFORM
SEBUAH PLATFORM MEMBACA YANG KUAT
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Kami tidak perlu menayangkan iklan, sehingga kami tidak perlu menahan anda di dalam aplikasi kami. Mastodon memiliki pilihan aplikasi pihak ketiga terbanyak sehingga anda mendapatkan pengalaman yang anda inginkan.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Berkat laman feed yang kronologis, anda dapat dengan mudah mengikuti update dan melakukan hal lain.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
Tidak perlu khawatir jika anda salah mengklik dan mengubah rekomendasi. Kami tidak mengatur apa yang anda ingit lihat, kami serahkan kepada anda yang mengontrolnya.
PROTOCOLS, NOT PLATFORMS
PROTOKOL, BUKAN PLATFORM
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Mastodon tidak seperti platform media sosial pada umumnya, tetapi dibangun pada protokol yang terdesentralisasi. Anda dapat mendaftar pada server resmi kami, atau memilih pihak ketiga untuk melayani data anda.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Berkat protokol, apapun yang anda pilih, anda tetap dapat berkomunikasi dengan pengguna di server Mastodon yang berbeda. Dengan satu akun, anda dapat berkomunikasi dengan pengguna dari platform fediverse yang lain.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Tidak puas dengan pilihan anda? Anda dapat selalu berpindah ke server Mastodon yang berbeda selagi membawa pengikut anda. Untuk pengguna yang serius, anda bahkan bisa menyimpan data pada infrastruktur sendiri, karena Mastodon ini open-source.
NON-PROFIT IN NATURE
NON-PROFIT
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon terdaftar sebagai lembaga non-profit di US dan Jerman. Kami tidak terdorong untuk memperoleh keuntungan, tetapi apa yang terbaik.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
SEPERTI YANG DILIHAT DI: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, dan lainnya.

View File

@@ -1 +1 @@
Where conversations happen
Tempat di mana percakapan terjadi

View File

@@ -1,61 +1,61 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon er besta leiðin til að fylgjast með hvað sé í gangi. Fylgstu með hverjum sem er í fediverse-heiminum og skoðaðu það allt í tímaröð. Engin algrím, auglýsingar eða smellbeitur á ferðinni.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Þetta er opinbera Android-forritið fyrir Mastodon. Það er eldsnöggt og fjarska fallegt, hannað til að vera bæði öflugt og auðvelt í notkun. Í forritinu okkar geturðu:
EXPLORE
KANNAÐ
Discover new writers, journalists, artists, photographers, scientists and more
■ See whats happening in the world
Uppgötvaðu nýja rithöfunda, blaðamenn, listafólk, ljósmyndara, vísindafólk og fleira
■ Sjáðu hvað er að gerast í heiminum
READ
LESIÐ
Keep up with people you care about in a chronological feed with no interruptions
■ Follow hashtags to keep up with specific topics in real time
Vertu í sambandi við fólk sem þér er kært á streymi í tímaröð án truflana
■ Fylgst með myllumerkjum til að fá upplýsingar um tiltekin efni í rauntíma
CREATE
SKAPAÐ
Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
Birt færslur til fylgjendanna þinna eða alls heimsins, með könnunum, hágæða myndum og myndskeiðum
Tekið þátt í áhugaverðum samræðum við annað fólk
CURATE
SKIPULAGT
Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
Búið til lista yfir fólk sem þú vilt ekki missa af færslum frá
Síað orð og setningar til að stýra hvað þú sérð og hvað ekki
AND MORE!
OG FLEIRA!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
Fallegt þema sem aðlagast persónusniðnu litastefi, ljóst eða dökkt
Deildu og skannaðu QR-kóða til að skiptast á Mastodon-notendasniðum við aðra
Skráðu þig inn og skiptu milli margra notendaaðganga
Með bjölluhnappnum geturðu fengið tilkynningar þegar tilteknir aðilar birta færslur
Ekkert sem afvegaleiðir! Þú getur sett færslurnar þínar á bakvið aðvörun vegna efnis
A POWERFUL PUBLISHING PLATFORM
ÖFLUGT KERFI TIL BIRTINGAR
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Þú þarft ekki lengur að prófa þig áfram með og friðþægja eitthvert ógagnsætt algrími sem ákvarðar hvort vinir þínir fái að sjá það sem þú birtir. Ef viðkomandi fylgist með þér, mun það sjást.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Ef þú birtir það á opna vefnum, er hægt að skoða það á opna vefnum. Þú ert örugg(ur) við að deila tenglum á Mastodon, vitandi það að hver sem er mun geta lesið þá án þess að skrá sig inn.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
Með samræðum, hágæða myndefni, myndskeiðum, hljóðskrám og viðvörunum vegna efnis, býður Mastodon upp á margar leiðir til að tjá þig á þann hátt sem þér hentar.
A POWERFUL READING PLATFORM
ÖFLUGT KERFI TIL LESTRAR
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Við þurfum ekkert að sýna þér auglýsingar og höfum því enga ástæðu til að halda þér inni í okkar eigin forritum. Mastodon býður upp á mikið úrval forrita frá utanaðkomandi aðilum og samþættingu við önnur kerfi, þannig að þú getir valið það sem þér líkar best.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Þökk sé heimastreymi í tímaröð, þá er auðvelt að sjá þegar þú lýkur við að skoða allar nýjar færslur og getur snúið þér að einhverju öðru.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
Þú þarft ekkert að hafa áhyggjur að einn smellur á rangan stað skemmi orðspor þitt að eilífu. Við eru ekkert að giska á hvað þú viljir sjá, við látum þér eftir að stýra því.
PROTOCOLS, NOT PLATFORMS
SAMSKIPTAMÁTAR, EKKI KERFI
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Mastodon er ekki hefðbundinn samfélagsmiðill, heldur byggist í kringum samskiptamáta sem ekki er með miðlæga stýringu. Þú getur skráð þig á opinbera netþjóninum okkar eða valið utanaðkomandi þjón til að hýsa gögnin þín og hafa umsjón með umhverfinu þínu.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Þökk sé sameiginlegum samskiptamáta, þá skiptir ekki máli hvaða netþjón þú velur; þú átt að eiga hindranalaus samskipti við fólk á öðrum Mastodon-þjónum. En það er meira til: Með einum notandaaðgangi geturðu átt í samskiptum við önnut tengd kerfi sem tilheyra fedi-heiminum.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Ekki ánægð/ur með valið þitt? Þú getur alltaf skipt yfir á annan Mastodon-þjón og tekið fylgjendurna þína með þér. Vanir tölvulæsir notendur geta meira að segja hýst sitt eigið kerfi, enda er Mastodon opinn hugbúnaður.
NON-PROFIT IN NATURE
ÁN HAGNAÐARMARKMIÐA INN AÐ BEINI
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon er skráð sem samtök án hagnaðarmarkmiða í BNA og Þýskalandi. Við höfum engan hvata til að ná peningum út úr kerfinu, heldur liggur áhuginn í því sem er best fyrir kerfið.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
EINS OG BIRST HEFUR Í: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com og víðar.

View File

@@ -1 +1 @@
Where conversations happen
Þar sem samræður eiga sér stað

View File

@@ -1,4 +1,4 @@
Mastodon è il modo migliore per tenere il passo con ciò che sta accadendo. Segui chiunque attraverso il fediverso e guarda tutto in ordine cronologico. No algorithms, ads, or clickbait in sight.
Mastodon è il modo migliore per tenere il passo con ciò che sta accadendo. Segui chiunque attraverso il fediverso e guarda tutto in ordine cronologico. Nessun algoritmo, pubblicità o clickbait in vista.
Questa è l'app Android ufficiale per Mastodon. È incredibilmente veloce e straordinariamente bella, progettata per essere non solo potente ma anche facile da usare. Nella nostra app, puoi:
@@ -50,7 +50,7 @@ PROTOCOLLI, NON PIATTAFORME
Mastodon non è come una piattaforma di social media tradizionale, ma è costruito su un protocollo decentralizzato. Puoi registrarti sul nostro server ufficiale o sceglierne uno di terze parti, per ospitare i tuoi dati e moderare la tua esperienza.
Grazie al protocollo comune, non importa cosa tu scelga, puoi comunicare senza problemi con le persone su altri server Mastodon. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Grazie al protocollo comune, non importa cosa tu scelga, puoi comunicare senza problemi con le persone su altri server Mastodon. Ma c'è di più: con un solo account puoi comunicare con persone di altre piattaforme del Fediverso.
Non sei felice della tua scelta? Puoi sempre passare a un altro server Mastodon portando con te i tuoi seguaci. Per gli utenti avanzati, puoi persino ospitare i tuoi dati sulla tua infrastruttura, poiché Mastodon è open source.

View File

@@ -1,61 +1,61 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon で世界に起きていることを探索しよう。 Fediverse の誰でもフォローして投稿を時系列で閲覧できます。 アルゴリズム、広告、クリックベイトはありません。
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
これは Mastodon の公式 Android アプリです。 パワフルで使いやすく、燃えるように高速で驚くほど美しいアプリです。 このアプリでできること:
EXPLORE
探索
Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
作家、写真家、科学者、ジャーナリスト、アーティストなど多様な人々に出会えます
世界で起きていることを目撃しましょう
READ
閲覧
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
邪魔するもののない時系列フィードで、注目している人々に追い付きましょう
ハッシュタグをフォローして、話題をリアルタイムで把握できます
CREATE
投稿
Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
投票、高画質の画像や動画をフォロワーや世界に投稿できます
人々との面白い会話にも参加できます
CURATE
整理
Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
投稿を見逃したくない人々はリストにまとめられます
見たくない単語やフレーズをフィルターに指定すれば、表示しません
AND MORE!
他にも!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
あなたの色、ライト/ダークに合わせた美しいテーマ
QR コードの共有とスキャンで、Mastodonプロファイルを素早く交換
複数のアカウントにログイン、切り替え
ベルボタンで、特定の人の投稿を通知
ネタバレなし! コンテンツ閲覧警告で隠して投稿
A POWERFUL PUBLISHING PLATFORM
強力な表現プラットフォームとして
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
ここでは、友達の投稿をあなたから非表示にする不透明なアルゴリズムの心配はありません。 フォローすれば、表示されます。
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
オープンウェブに公開で投稿するだけで、投稿にオープンウェブからアクセスできます。 Mastodon へのリンクを共有すれば、ログインなしで誰でも読めて問題なく知識を共有できます。
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
スレッド、投票、高画質の画像、動画、音声、コンテンツの閲覧警告も含め、Mastodon はあなた自身を表現する最適な方法を提供しています。
A POWERFUL READING PLATFORM
強力な閲覧プラットフォームとして
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
広告を表示しなくてよいので、公式アプリ以外の選択も尊重します。Mastodon にはサードパーティのアプリや外部統合の豊富な選択肢があり、最適な体験を選択できます。
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
時系列ホームフィードなら、新しい投稿をすべて読み終わったか簡単にわかります。
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
ミスクリックのせいで、興味がないおすすめを永遠に表示される心配はありません。 あなたが見たいものを私たちが推測したりせず、あなた自身の制御に委ねます。
PROTOCOLS, NOT PLATFORMS
プラットフォームではなくプロトコル
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Mastodon は従来のソーシャルメディアプラットフォームとは違い、非中央集権プロトコル上に構築されています。 私たちの公式サーバーに登録するか、サードパーティーのサーバーにデータをホストしてモデレーションに従うことも選択できます。
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
あなたがどのサーバーを選択しても、共通プロトコルにより他の Mastodon サーバーの人々とシームレスに通信できます。 それだけでなく、他の Fediverse プラットフォームの人々とも交流できます。
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
選択に満足できなくても大丈夫です! いつでもフォロワーを引き継いだまま別のサーバーに引っ越せます。 Mastodon はオープンソースのため、上級ユーザーであれば自前でデータをホスティングできます。
NON-PROFIT IN NATURE
生まれながらに非営利
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon はアメリカとドイツで非営利団体として登録されています。 私たちはプラットフォームから金銭的な価値を生み出すことではない、プラットフォームにとってよりよい目的を追求しています。
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
TIMEForbesWiredThe GuardianCNNThe VergeTechCrunchFinancial TimesGizmodoPCMAG.com などで紹介されました。

View File

@@ -1 +1 @@
Where conversations happen
話題が生まれる場所

View File

@@ -1,4 +1,4 @@
„Mastodon“ tai geriausias būdas sekti, kas vyksta. Sek bet kurį asmenį visoje fediverse ir žiūrėk viską chronologine tvarka. Jokių algoritmų, reklamų ar tyčinių paspaudimų.
„Mastodon“ tai geriausias būdas sekti, kas vyksta. Sek bet kurį asmenį visoje fediversijoje ir žiūrėk viską chronologine tvarka. Jokių algoritmų, reklamų ar tyčinių paspaudimų.
Tai oficiali „Mastodon“, skirto „Android“ programėlė. Ji yra labai sparti ir nuostabiai graži, sukurta taip, kad būtų ne tik galinga, bet ir paprasta naudoti. Mūsų programėlėje galima:
@@ -42,7 +42,7 @@ GALINGA SKAITYMO PLATFORMA
Mums nereikia rodyti reklamų, todėl mums nereikia tave laikyti savo programėlėje. „Mastodon“ turi gausiausią trečiųjų šalių programėlių ir integracijų pasirinkimą, tad gali pasirinkti tau tinkamiausią patirtį.
Dėl chronologinio pagrindinio srauto lengva nustatyti, kada jau esi pasiekęs (-usi) visus naujinimus ir gali pereiti prie ko nors kito.
Dėl chronologinio pagrindinio srauto lengva nustatyti, kada jau pasiekei visas naujienas ir gali pereiti prie ko nors kito.
Nereikia nerimauti, kad neteisingas spustelėjimas sugadins tavo rekomendacijas visiems laikams. Mes nenuspėjame, ką nori matyti, o leidžiame tau tai valdyti.
@@ -50,9 +50,9 @@ PROTOKOLAI, O NE PLATFORMOS
„Mastodon“ nėra panaši į tradicinę socialinės medijos platformą, bet sukurta pagal decentralizuotą protokolą. Gali užsiregistruoti mūsų oficialiame serveryje arba pasirinkti trečiąją šalį, kuri patalpins tavo duomenis ir palengvins patirtį.
Dėl bendro protokolo, nesvarbu, ką pasirinktum, gali sklandžiai bendrauti su žmonėmis, esančiais kituose „Mastodon“ serveriuose. Bet yra ir daugiau: naudojant tik viena paskyra gali bendrauti su žmonėmis iš kitų fediversų platformų.
Dėl bendro protokolo, nesvarbu, ką pasirinktum, gali sklandžiai bendrauti su žmonėmis kituose „Mastodon“ serveriuose. Bet yra ir daugiau: su tik viena paskyra gali bendrauti su žmonėmis iš kitų fediversų platformų.
Nesi patenkintas (-a) savo pasirinkimu? Visada gali pereiti į kitą „Mastodon“ serverį ir kartu su savimi pasiimti sekėjus. Pažengę naudotojai gali net talpinti duomenis savo infrastruktūroje, nes „Mastodon“ yra atvirojo kodo.
Nepatenkinti savo pasirinkimu? Visada gali pereiti į kitą „Mastodon“ serverį ir kartu su savimi pasiimti sekėjus. Patyrę naudotojai gali net talpinti duomenis savo infrastruktūroje, nes „Mastodon“ yra atvirojo kodo.
NE PELNO SIEKIANTIS POBŪDIS

View File

@@ -1,61 +1,61 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon is de beste manier om op de hoogte te blijven van wat er gebeurt. Volg iedereen in de fediverse en zie alles in chronologische volgorde. Geen algoritmes, advertenties of clickbait te bekennen.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Dit is de officiële Android-app voor Mastodon. Het is razendsnel en verbluffend mooi. Ontworpen om niet alleen krachtig, maar ook gebruiksvriendelijk te zijn. In onze app kun je:
EXPLORE
VERKENNEN
Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
Nieuwe schrijvers, journalisten, kunstenaars, fotografen, wetenschappers en meer ontdekken
Zie wat er in de wereld gebeurt
READ
LEZEN
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
Op de hoogte blijven van mensen om wie je geeft, op een chronologische tijdlijn en zonder onderbrekingen
Hashtags in realtime volgen om op de hoogte te blijven van specifieke onderwerpen
CREATE
CREËREN
Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
Berichten naar alleen je volgers sturen of naar de hele wereld, met peilingen, afbeeldingen van hoge kwaliteit en video's
Aan interessante gesprekken met andere mensen deelnemen
CURATE
CUREREN
Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
Lijsten maken met mensen die je volgt, om zo nooit een bericht te missen
Woorden of zinnen filteren om te bepalen wat je wel en niet wilt zien
AND MORE!
EN MEER!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
Een prachtig thema dat zich aanpast aan je persoonlijke kleurenschema, licht of donker
■ QR-codes scannen om snel Mastodon-profielen met andere mensen te delen
Meerdere accounts gebruiken
Meldingen van specifiek personen ontvangen, wanneer deze berichten plaatsen
Geen spoilers! ■ Je kunt je berichten achter inhoudswaarschuwingen plaatsen
A POWERFUL PUBLISHING PLATFORM
EEN KRACHTIG PUBLICATIEPLATFORM
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Je hoeft niet langer te proberen een ondoorzichtig algoritme tevreden te stellen, dat beslist of je vrienden wel of niet mogen zien wat je hebt geplaatst. Als ze je volgen, zullen ze het zien.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Wanneer je het in de fediverse plaatst, is het ook toegankelijk in de fediverse. Je kunt veilig links naar Mastodon delen, in de wetenschap dat iedereen ze kan lezen zonder in te hoeven loggen.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
Met gesprekken, peilingen, afbeeldingen van hoge kwaliteit, video's, audio en inhoudswaarschuwingen biedt Mastodon genoeg manieren om jezelf te kunnen uiten, op een manier die bij jou past.
A POWERFUL READING PLATFORM
EEN KRACHTIG LEESPLATFORM
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
We hoeven je geen advertenties te laten zien, dus we hoeven je ook niet voor onze app te behouden. Mastodon heeft de rijkste keuze aan door derden ontwikkelde apps en integraties, zodat je de gebruikerservaring kunt kiezen die het beste bij je past.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Dankzij de chronologische tijdlijn is het makkelijk om te zien wanneer je alle updates hebt bekeken en met iets anders kunt verder gaan.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
Je hoeft niet bang te zijn dat wanneer je op iets verkeerds klikt, je aanbevelingen voor altijd zijn verpest. We gissen niet naar wat je wilt zien, we laten het aan jou over.
PROTOCOLS, NOT PLATFORMS
PROTOCOLLEN, GEEN PLATFORMS
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Mastodon is niet zoals een traditioneel social media platform, maar is gebouwd op een gedecentraliseerd protocol. Je kunt voor onze officiële server of voor eentje van een derde partij kiezen om je gegevens te hosten en gebruikers te modereren.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Dankzij het gemeenschappelijke protocol kun je, ongeacht wat je kiest, naadloos met mensen op andere Mastodon-servers communiceren. Maar er is meer: Met slechts één account kun je met mensen van andere fediverse-platforms communiceren.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Niet tevreden met je keuze? Je kunt altijd naar een andere Mastodon-server overstappen en je volgers meenemen. Gevorderde gebruikers kunnen hun gegevens zelfs op hun eigen infrastructuur hosten, aangezien Mastodon open-source is.
NON-PROFIT IN NATURE
NON-PROFIT VAN AARD
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon is een geregistreerde non-profit organisatie in de Verenigde Staten en Duitsland. We halen onze motivatie niet uit het commercieel uitbuiten van Mastodon, maar uit wat het beste is voor Mastodon.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
VERMELD IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com en meer.

View File

@@ -1 +1 @@
Where conversations happen
Waar gesprekken ontstaan

View File

@@ -0,0 +1,61 @@
O Mastodon é a melhor maneira de acompanhar o que está acontecendo. Siga qualquer pessoa durante o fediverso e veja tudo em ordem cronológica. Sem algoritmos, anúncios ou clickbait em vista.
Este é o aplicativo oficial do Mastodon para Android. Está a explodir rapidamente e incrivelmente bonito, projetado para ser não só poderoso mas também fácil de usar. Em nosso aplicativo, você pode:
EXPLORAR
Descobrir novos escritores, jornalistas, artistas, fotógrafos, cientistas e muito mais
Veja o que está acontecendo no mundo 🌎
LEIA
Mostra com as pessoas que você se importa em um feed cronológico e sem interrupções
Siga hashtags para acompanhar tópicos específicos em tempo real
CRIE
Publique para os seus seguidores ou para o mundo inteiro: pesquisas, imagens e vídeos de alta qualidade
Participe de conversas interessantes com outras pessoas
CURE
★ Crie uma lista de pessoas para nunca mais perder uma publicação
+ Filtre palavras ou frases para controlar o que você faz e o que não quer ver
E MAIS!
★ Um belo tema que se adapta ao seu esquema personalizado de cores, claro ou escuro
Compartilhe e digitalize os códigos QR para trocar rapidamente os perfis de Mastodon com outros
Entre e alterne entre várias contas
Seja notificado quando uma pessoa fizer uma publicação específica com o botão do sino 🔔
Nenhum spoiler! Você pode colocar as suas publicações atrás de avisos de conteúdo
UMA PLATAFORMA DE PUBLICAÇÃO PODEROSA ✨
Você não precisa mais tentar apaziguar um algoritmo opaco que decide se seus amigos vão ver o que você postou. Se seguirem você, verão isso.
Se você publicá-lo na web aberta, ele é acessível na web aberta. Você pode compartilhar com segurança links para o Mastodon sabendo que qualquer pessoa será capaz de lê-los sem fazer o login.
Entre threads, pesquisas, imagens de alta qualidade, vídeos, avisos de áudio e conteúdo, Mastodon oferece muitas maneiras de se expressar de uma forma que melhor lhe convém.
UMA PLATAFORMA DE LEITURA PODEROSA ✨
Não precisamos lhe mostrar anúncios, então não precisamos te manter em nosso aplicativo. O Mastodon tem a seleção mais rica de apps de terceiros e integrações para que você possa escolher a melhor experiência para você.
Graças ao feed cronológico, é fácil dizer quando se encontra em todas as atualizações e pode ir para outra coisa.
Não há necessidade de se preocupar com que um clique errado irá arruinar as suas recomendações para sempre. Não adivinhamos o que você quer ver, deixamos que você o controle.
PROTOCOLOS, NÃO PLATAFORMAS
O Mastodon não é como uma plataforma de mídia social tradicional, mas é construído em um protocolo descentralizado. Você pode se inscrever em nosso servidor oficial ou escolher um terceiro para disponibilizar seus dados e moderar sua experiência.
Graças ao protocolo comum, não importa o que escolher, você pode se comunicar perfeitamente com as pessoas de outros servidores Mastodon. E têm mais: com apenas uma conta, você pode se comunicar com pessoas de outras plataformas fediversas.
Não está satisfeito com sua escolha? Você sempre pode mudar para um servidor Mastodon diferente enquanto leva seus seguidores com você. Para usuários avançados, você pode até mesmo hospedar seus dados em sua própria infraestrutura, já que o Mastodon é de código aberto.
SEM FINS LUCRATIVOS
Mastodon é uma instituição sem fins lucrativos registada nos EUA e na Alemanha. Nós não somos motivados extraindo o valor monetário da plataforma, mas pelo que é melhor para a plataforma.
DESTAQUE EM: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com e muito mais.

View File

@@ -0,0 +1 @@
Onde as conversas acontecem

View File

@@ -1,4 +1,4 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
O Mastodon é a melhor maneira de manter com que está a acontecer. Segue qualquer um durante o fediverso e vê tudo em ordem cronológica. No algorithms, ads, or clickbait in sight.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:

View File

@@ -1,61 +1,61 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon - лучший способ быть в курсе всего происходящего. Следуйте за любым человеком по всей федеральной вселенной и смотрите все в хронологическом порядке. Никаких алгоритмов, рекламы или кликбейта.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Это официальное приложение для Android от Mastodon. Он молниеносно быстрый и потрясающе красивый, разработанный, чтобы быть не только мощным, но и простым в использовании. В нашем приложении вы можете:
EXPLORE
ИССЛЕДУЙТЕ
Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
Откройте для себя новых писателей, журналистов, художников, фотографов, ученых и многое другое
Узнайте, что происходит в мире
READ
ЧИТАТЬ
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
Следите за людьми, которые вам интересны, в хронологической ленте без прерываний
Следите за хэштегами, чтобы быть в курсе конкретных тем в режиме реального времени
CREATE
СОЗДАТЬ
Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
Отправьте сообщение своим последователям или всему миру, используя опросы, высококачественные изображения и видео
Участвуйте в интересных беседах с другими людьми
CURATE
КУРАТОР
Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
Создавайте списки людей, чтобы не пропустить ни одного сообщения
Фильтруйте слова и фразы, чтобы контролировать то, что вы хотите и не хотите видеть
AND MORE!
И БОЛЬШЕ!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
Красивая тема, которая адаптируется к вашей индивидуальной цветовой схеме, светлой или темной
Обменивайтесь и сканируйте QR-коды, чтобы быстро обмениваться профилями Mastodon с другими людьми
Вход в систему и переключение между несколькими учетными записями
Получайте уведомления о сообщениях конкретного человека с помощью кнопки "звонок"
Никаких спойлеров! Вы можете поместить свои сообщения за предупреждениями о содержании
A POWERFUL PUBLISHING PLATFORM
МОЩНАЯ ИЗДАТЕЛЬСКАЯ ПЛАТФОРМА
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Вам больше не нужно пытаться угодить непрозрачному алгоритму, который решает, увидят ли ваши друзья то, что вы опубликовали. Если они будут следить за вами, то увидят это.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Если вы публикуете его в открытом интернете, он становится доступным в открытом интернете. Вы можете смело делиться ссылками на Mastodon, не сомневаясь, что любой пользователь сможет прочитать их, не заходя на сайт.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
Благодаря темам, опросам, высококачественным изображениям, видео, аудио и предупреждениям о содержании, Mastodon предлагает множество способов выразить себя так, как вам удобно.
A POWERFUL READING PLATFORM
МОЩНАЯ ПЛАТФОРМА ДЛЯ ЧТЕНИЯ
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Нам не нужно показывать вам рекламу, поэтому нам не нужно удерживать вас в нашем приложении. У Mastodon самый богатый выбор сторонних приложений и интеграций, поэтому вы можете выбрать то, что подходит вам больше всего.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Благодаря хронологической главной ленте легко определить, когда вы проследили за всеми обновлениями и можете переходить к чему-то другому.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
Не нужно беспокоиться, что один неверный щелчок навсегда испортит ваши рекомендации. Мы не угадываем, что вы хотите увидеть, мы позволяем вам управлять этим.
PROTOCOLS, NOT PLATFORMS
ПРОТОКОЛЫ, А НЕ ПЛАТФОРМЫ
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Mastodon не похож на традиционную платформу социальных сетей, он построен на децентрализованном протоколе. Вы можете зарегистрироваться на нашем официальном сервере или выбрать стороннюю компанию для размещения ваших данных и модерации вашего опыта.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Благодаря общему протоколу, независимо от того, что вы выберете, вы сможете легко общаться с людьми на других серверах Mastodon. Но это еще не все: С помощью одной учетной записи вы можете общаться с людьми с других платформ fediverse.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Не довольны своим выбором? Вы всегда можете перейти на другой сервер Mastodon, забрав с собой своих подписчиков. Опытные пользователи могут даже размещать свои данные на собственной инфраструктуре, поскольку Mastodon имеет открытый исходный код.
NON-PROFIT IN NATURE
НЕКОММЕРЧЕСКИЙ ХАРАКТЕР
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon является зарегистрированной некоммерческой организацией в США и Германии. Мы руководствуемся не стремлением извлечь из платформы денежную выгоду, а тем, что лучше для платформы.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
Опубликованы в: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com и других.

View File

@@ -1 +1 @@
Where conversations happen
Где происходят беседы

View File

@@ -0,0 +1,61 @@
Mastodon is the best way to keep up with whats happening. Sledujte kohokoľvek naprieč fediversom a prezerajte všetko chronologicky. No algorithms, ads, or clickbait in sight.
Toto je oficiálna Mastodon aplikácia pre Android. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
EXPLORE
■ Discover new writers, journalists, artists, photographers, scientists and more
■ See whats happening in the world
READ
■ Keep up with people you care about in a chronological feed with no interruptions
■ Follow hashtags to keep up with specific topics in real time
CREATE
■ Post to your followers or the whole world, with polls, high quality images and videos
■ Participate in interesting conversations with other people
CURATE
■ Create lists of people to never miss a post
■ Filter words or phrases to control what you do and dont want to see
AND MORE!
■ A beautiful theme that adapts to your personalized color scheme, light or dark
■ Share and scan QR codes to quickly exchange Mastodon profiles with others
■ Login and switch between multiple accounts
■ Get notified when a specific person posts with the bell button
■ No spoilers! You can put your posts behind content warnings
A POWERFUL PUBLISHING PLATFORM
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
A POWERFUL READING PLATFORM
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
PROTOCOLS, NOT PLATFORMS
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
NON-PROFIT IN NATURE
Mastodon je nezisková organizácia registrovaná v Spojených Štátoch a Nemecku. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.

View File

@@ -0,0 +1 @@
Where conversations happen

View File

@@ -2,7 +2,7 @@ Mastodon is the best way to keep up with whats happening. Follow anyone acros
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
EXPLORE
UTFORSKA
■ Discover new writers, journalists, artists, photographers, scientists and more
■ See whats happening in the world
@@ -12,7 +12,7 @@ READ
■ Keep up with people you care about in a chronological feed with no interruptions
■ Follow hashtags to keep up with specific topics in real time
CREATE
SKAPA
■ Post to your followers or the whole world, with polls, high quality images and videos
■ Participate in interesting conversations with other people

View File

@@ -1,36 +1,36 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon เป็นวิธีที่ดีที่สุดที่จะติดตามสิ่งที่กำลังเกิดขึ้น ติดตามใครก็ตามทั่วทั้งจักรวาลสหพันธ์และดูจักรวาลสหพันธ์ทั้งหมดตามลำดับเวลา ไม่มีอัลกอริทึม, โฆษณา หรือคลิกเบตอยู่ในสายตา
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
นี่คือแอป Android อย่างเป็นทางการสำหรับ Mastodon แอปรวดเร็วมากและสวยงามอย่างน่าทึ่ง ได้รับการออกแบบให้ไม่ใช่แค่ทรงพลังแต่ยังใช้งานง่ายอีกด้วย ในแอปของเรา คุณสามารถ:
EXPLORE
สำรวจ
Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
ค้นพบนักเขียน, นักข่าว, ศิลปิน, ช่างภาพ, นักวิทยาศาสตร์ และอื่น ๆ ใหม่ ๆ
ดูสิ่งที่กำลังเกิดขึ้นในโลก
READ
อ่าน
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
ติดตามผู้คนที่คุณห่วงใยในฟีดตามลำดับเวลาโดยไม่มีการขัดจังหวะ
ติดตามแฮชแท็กเพื่อติดตามหัวข้อที่เฉพาะเจาะจงตามเวลาจริง
CREATE
สร้าง
Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
โพสต์ไปยังผู้ติดตามของคุณหรือทั้งโลก พร้อมการสำรวจความคิดเห็น, ภาพคุณภาพสูง และวิดีโอ
มีส่วนร่วมในการสนทนาที่น่าสนใจกับผู้คนอื่น ๆ
CURATE
เรียบเรียง
Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
สร้างรายการผู้คนเพื่อไม่พลาดโพสต์ใด
กรองคำหรือวลีเพื่อควบคุมสิ่งที่คุณต้องการและไม่ต้องการเห็น
AND MORE!
และอื่น ๆ!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
ชุดรูปแบบที่สวยงามที่ปรับให้เข้ากับแบบแผนชุดสีเฉพาะบุคคลของคุณ สว่างหรือมืด
แชร์และสแกนรหัส QR เพื่อแลกเปลี่ยนโปรไฟล์ Mastodon กับผู้อื่นอย่างรวดเร็ว
เข้าสู่ระบบและสลับระหว่างหลายบัญชี
รับการแจ้งเตือนเมื่อบุคคลที่เฉพาะเจาะจงโพสต์ด้วยปุ่มกระดิ่ง
ไม่มีผู้สปอยล์! คุณสามารถนำโพสต์ของคุณไว้หลังคำเตือนเนื้อหา
A POWERFUL PUBLISHING PLATFORM
แพลตฟอร์มการเผยแพร่ที่ทรงพลัง
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
@@ -38,7 +38,7 @@ If you publish it to the open web, its accessible on the open web. You can sa
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
A POWERFUL READING PLATFORM
แพลตฟอร์มการอ่านที่ทรงพลัง
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
@@ -46,16 +46,16 @@ Thanks to the chronological home feed, its easy to tell when youve caught
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
PROTOCOLS, NOT PLATFORMS
โปรโตคอล ไม่ใช่แพลตฟอร์ม
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
ไม่พอใจกับตัวเลือกของคุณ? คุณสามารถสลับเป็นเซิร์ฟเวอร์ Mastodon อื่นได้เสมอพร้อมนำผู้ติดตามของคุณไปกับคุณ สำหรับผู้ใช้ขั้นสูง คุณยังสามารถโฮสต์ข้อมูลของคุณบนโครงสร้างพื้นฐานของคุณเองได้อีกด้วย เนื่องจาก Mastodon เป็นโอเพนซอร์ส
NON-PROFIT IN NATURE
ไม่แสวงหาผลกำไรโดยธรรมชาติ
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon เป็นองค์กรไม่แสวงหาผลกำไรที่จดทะเบียนในสหรัฐอเมริกาและเยอรมนี We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
ตามที่นำเสนอใน: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com และอื่น ๆ

View File

@@ -1 +1 @@
Where conversations happen
ที่ซึ่งการสนทนาเกิดขึ้น

View File

@@ -1,16 +1,16 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Olan biteni takip etmenin en iyi yolu. Herhangi birini federe ağında takip edin ve her şeyi kronolojik sırayla görün. Görünürde algoritma, reklam veya tıklama tuzağı yok.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Bu, aşağıdakiler için resmi uygulamasıdır. Sadece güçlü değil aynı zamanda kullanımı kolay olacak şekilde tasarlanmış, son derece hızlı ve şaşırtıcı derecede güzel. Uygulamamızda şunları yapabilirsiniz:
EXPLORE
KEŞFET
Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
Yeni yazarlar, gazeteciler, sanatçılar, fotoğraılar, bilim insanları ve daha fazlasını keşfedin
Dünyada neler olup bittiğini görün
READ
OKU
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
Önem verdiğiniz kişileri kesintisiz bir kronolojik akışta takip edin
Belirli konuları gerçek zamanlı olarak takip etmek için etiketleri takip edin
CREATE
@@ -25,37 +25,37 @@ CURATE
AND MORE!
■ A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
Profillerini başkalarıyla hızlıca paylaşmak için QR kodlarını paylaşın ve tarayın
Giriş yapın ve birden fazla hesap arasında geçiş yapın
Zil butonu ile belirli bir kişi paylaşım yaptığında bildirim alın
İpucu yok! Yayınlarınızı içerik uyarılarının arkasına koyabilirsiniz
A POWERFUL PUBLISHING PLATFORM
GÜÇLÜ BIR YAYINCILIK PLATFORMU
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Artık arkadaşlarınızın paylaştıklarını görüp görmeyeceğine karar veren şeffaf olmayan bir algoritmayı yatıştırmaya çalışmak zorunda değilsiniz. Sizi takip ederlerse görürler.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Eğer bunu açık olarak yayınlarsanız, herkese açık olarak erişilebilir olur. Herkesin giriş yapmadan okuyabileceğinden emin olarak bağlantılarını güvenle paylaşabilirsiniz.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
Başlıklar, anketler, yüksek kaliteli görüntüler, videolar, sesler ve içerik uyarıları arasında, kendinizi size uygun bir şekilde ifade etmenin birçok yolunu sunar.
A POWERFUL READING PLATFORM
GÜÇLÜ BİR OKUMA PLATFORMU
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Size reklam göstermemize gerek yok, bu yüzden sizi uygulamamızda tutmamıza da gerek yok. Sosyal ağımız, size en uygun deneyimi seçebileceğiniz en zengin 3. parti uygulama ve entegrasyon seçeneklerine sahiptir.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Kronolojik ana sayfa akışı sayesinde, tüm güncellemeleri ne zaman yakaladığınızı ve başka bir şeye geçebileceğinizi anlamak kolaydır.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
Yanlış bir tıklamanın önerilerinizi sonsuza dek mahvedeceğinden endişelenmenize gerek yok. Ne görmek istediğinizi tahmin etmiyoruz, sizin kontrol etmenize izin veriyoruz.
PROTOCOLS, NOT PLATFORMS
PLATFORMLAR DEĞİL, PROTOKOLLER
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Sosyal ağımız geleneksel bir sosyal medya platformu gibi değil, merkezi olmayan bir protokol üzerine inşa edilmiştir. Resmi sunucumuza kayıt olabilir veya verilerinizi barındırmak ve deneyiminizi denetlemek için 3. bir taraf seçebilirsiniz.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Ortak protokol sayesinde, neyi seçerseniz seçin, diğer sunucularındaki kişilerle sorunsuz bir şekilde iletişim kurabilirsiniz. Ama dahası da var: Sadece tek bir hesapla, diğer federe platformlarındaki kişilerle iletişim kurabilirsiniz.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Seçimden memnun değil misiniz? Takipçilerini yanınızda götürürken her zaman farklı bir sunucusuna geçebilirsiniz. İleri düzey kullanıcılar için, Açık kaynaklı olduğundan verilerinizi kendi altyapınızda bile barındırabilir.
NON-PROFIT IN NATURE
KÂR AMACI GÜTMEYEN NİTELİKTE
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastıdon,ABD ve Almanya'da kâr amacı gütmeyen kayıtlı bir kuruluştur. Platformdan parasal değer elde etmek için değil, platform için en iyi olanı yapmak için motive oluyoruz.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
YER ALDIĞI GİBİ: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, ve dahası.

View File

@@ -1 +1 @@
Where conversations happen
Konuşmaların gerçekleştiği yer

View File

@@ -1,61 +1,61 @@
Mastodon is the best way to keep up with whats happening. Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.
Mastodon найкращий спосіб бути в курсі подій. Слідкуйте за ким завгодно у всьому fediverse та дивіться все в хронологічному порядку. Немає алгоритмів, реклами чи наживки для натискань.
This is the official Android app for Mastodon. It is blazing fast and stunningly beautiful, designed to be not just powerful but also easy to use. In our app, you can:
Це офіційний застосунок для Android для Mastodon. Він блискавично швидкий і приголомшливо красивий, розроблений, щоб бути не тільки потужним, але й простим у використанні. У нашому застосунку ви можете:
EXPLORE
ДОСЛІДЖУВАТИ
Discover new writers, journalists, artists, photographers, scientists and more
See whats happening in the world
Відкрийте для себе нових письменників, журналістів, художників, фотографів, науковців та інших
Подивіться, що відбувається у світі
READ
ЧИТАТИ
Keep up with people you care about in a chronological feed with no interruptions
Follow hashtags to keep up with specific topics in real time
Будьте в курсі людей, які вам небайдужі, у хронологічній стрічці без переривання
Слідкуйте за хеш-тегами, щоб бути в курсі певних тем у реальному часі
CREATE
СТВОРЮВАТИ
Post to your followers or the whole world, with polls, high quality images and videos
Participate in interesting conversations with other people
Публікуйте дописи для своїх підписників або для всього світу з опитуваннями, високоякісними зображеннями та відео
Беріть участь у цікавих бесідах з іншими людьми
CURATE
КЕРУВАТИ
Create lists of people to never miss a post
Filter words or phrases to control what you do and dont want to see
Створюйте списки людей, щоб ніколи не пропускати публікації
Фільтруйте слова чи фрази, щоб контролювати, що ви робите, а що не хочете бачити
AND MORE!
І БІЛЬШЕ!
A beautiful theme that adapts to your personalized color scheme, light or dark
Share and scan QR codes to quickly exchange Mastodon profiles with others
Login and switch between multiple accounts
Get notified when a specific person posts with the bell button
No spoilers! You can put your posts behind content warnings
Красива тема, яка адаптується до вашої персоналізованої колірної схеми, світлої чи темної
Діліться та скануйте QR-коди, щоб швидко обмінюватися профілями Mastodon з іншими
Увійдіть і перемикайтеся між кількома обліковими записами
Отримуйте сповіщення, коли певна особа публікує повідомлення за допомогою кнопки дзвінка
Без спойлерів! Ви можете розміщувати свої публікації з попередженням про вміст
A POWERFUL PUBLISHING PLATFORM
ПОТУЖНА ПЛАТФОРМА ПУБЛІКАЦІЙ
You no longer have to try and appease an opaque algorithm that decides if your friends are going to see what you posted. If they follow you, theyll see it.
Вам більше не потрібно намагатися заспокоїти непрозорий алгоритм, який вирішує, чи побачать ваші друзі те, що ви опублікували. Якщо вони слідкують за вами, вони це побачать.
If you publish it to the open web, its accessible on the open web. You can safely share links to Mastodon in the knowledge that anyone will be able to read them without logging in.
Якщо ви опублікуєте його у відкритому інтернеті, він стане доступним у відкритому інтернеті. Ви можете сміливо ділитися посиланнями на Mastodon, знаючи, що будь-хто зможе їх прочитати, не авторизуючись.
Between threads, polls, high quality images, videos, audio, and content warnings, Mastodon offers plenty of ways to express yourself in a way that suits you.
Окрім тем, опитувань, високоякісних зображень, відео, аудіо та попереджень щодо вмісту, Mastodon пропонує безліч способів виразити себе у спосіб, який вам підходить.
A POWERFUL READING PLATFORM
ПОТУЖНА ПЛАТФОРМА ДЛЯ ЧИТАННЯ
We dont need to show you ads, so we dont need to keep you in our app. Mastodon has the richest selection of 3rd party apps and integrations so you can choose the experience that fits you best.
Нам не потрібно показувати вам рекламу, тому нам не потрібно тримати вас у нашому додатку. Mastodon має найбагатший вибір сторонніх додатків та інтеграцій, тож ви можете вибрати той досвід, який вам найбільше підходить.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Завдяки хронологічній домашній стрічці легко визначити, коли ви наздогнали всі оновлення та можете перейти до чогось іншого.
No need to worry that a misclick will ruin your recommendations forever. We dont guess what you want to see, we let you control it.
Не потрібно хвилюватися, що неправильне натискання назавжди зіпсує ваші рекомендації. Ми не вгадуємо, що ви хочете побачити, ми дозволяємо вам контролювати це.
PROTOCOLS, NOT PLATFORMS
ПРОТОКОЛИ, А НЕ ПЛАТФОРМИ
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Mastodon не схожий на традиційну платформу соціальних мереж, він побудований на основі децентралізованого протоколу. Ви можете зареєструватися на нашому офіційному сервері або вибрати третю сторону для розміщення ваших даних і модерування вашого досвіду.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Завдяки загальному протоколу, незалежно від того, що ви виберете, ви можете безперешкодно спілкуватися з людьми на інших серверах Mastodon. Але є ще більше: Лише з одним обліковим записом ви можете спілкуватися з людьми з інших платформ fediverse.
Not happy with your choice? You can always switch to a different Mastodon server while taking your followers with you. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Не задоволені своїм вибором? Ви завжди можете перейти на інший сервер Mastodon, взявши з собою підписників. Для досвідчених користувачів ви навіть можете розмістити свої дані у власній інфраструктурі, оскільки Mastodon є відкритим кодом.
NON-PROFIT IN NATURE
НЕПРИБУТКОВИЙ ХАРАКТЕР
Mastodon is a registered non-profit in the US and Germany. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon є зареєстрованою неприбутковою організацією в США та Німеччині. Нас мотивує не отримання грошової цінності з платформи, а те, що найкраще для платформи.
AS FEATURED IN: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com, and more.
ПРЕДСТАВЛЕНО В: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com тощо.

View File

@@ -1 +1 @@
Where conversations happen
Де відбуваються розмови

View File

@@ -0,0 +1,61 @@
Mastodon 是了解最新动态的最佳途径。 横跨联邦宇宙关注其他人,并在一个时间顺序中查看。 没有算法、广告或诱导链接。
这是 Mastodon 官方的 Android 应用程序。 它风驰电掣般地快而且让你惊叹的美丽,拥有强大而易用的设计。 在我们的应用中,您可以:
探索新鲜事
■ 发现新的作家、记者、画家、摄影师和科学家以及更多
■ 看看世界上正在发生什么
阅读
■ 在时间顺序流中跟上你关心的人,没有打断
■ 关注标签以实时关注具体主题
创建
■ 用投票、高质量图像和视频向粉丝或整个世界发嘟
■ 与其他人一起参与有趣的对话
组织与整理
■ 创建用户列表,不错过任何帖子
■ 利用单词与短语过滤功能来控制你想看到什么
还有更多!
■ 一个美丽的主题,符合您的个性化主题色,无论明亮或黑暗
■ 分享并扫描二维码以便与其他人快速交换 Mastodon 个人资料
■ 登录并在多个账户间切换
■ 点铃铛按钮,获得特定的人发嘟时的通知
■ 禁止剧透! 你可以将你的嘟文键入内容警告中
强大的发表平台
你不再需要尝试迎合不透明的算法,来决定你的朋友是否能看到你发布的内容。 如果朋友们关注你,他们就会看到嘟文。
如果你在一个公开的网络上发布嘟文,那嘟文就可以在那里访问。 你可以安全地分享到 Mastodon 的链接,知道任何人都可以在不登录的情况下阅读它们。
在讨论串、投票、高质量图像、视频、音频和内容警告之中Mastodon 提供了大量适合你的表达方式。
强大的阅读平台
我们无需向您展示广告,所以我们不会挽留让您留在我们的应用中。 Mastodon 有最丰富的第三方应用和集成,您可以选择最适合您的体验。
感谢按时间顺序提供的首页流,你很容易就能知道自己什么时候看完了所有的更新,可以继续看别的东西了。
永远不用担心点一下喜欢就会污染你的推荐列表。 我们不猜你想看到什么,我们让你自己控制它。
成为一种协议,而非平台
Mastodon 不像传统的社交媒体平台,而是建立在一个去中心化的协议之上。 您可以在我们的官方服务器上注册,或者选择第三方托管您的数据并保持相似的体验。
感谢同样的协议,不管你选择哪个服务器,你都可以与其他 Mastodon 服务器上与人无缝跨服聊天。 并且:只要同一个帐户,您就可以与其他联邦宇宙的人通信。
对你的选择不满意吗? 您随时可以带着您的粉丝切换到另一个 Mastodon 服务器。 对于进阶用户,你甚至可以在您自己的基础设施上托管您的数据,因为 Mastodon 是开源的。
天生非盈利性
Mastodon 是在美国与德国注册的非营利机构。 我们的初衷不是从平台上提取金钱价值,而是为了打造最好的给平台。
目前入驻《时代》、《福布斯》、《连线》、The Guardian、美国有线电视新闻网、The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com还有更多。

View File

@@ -0,0 +1 @@
对话发生的场所

View File

@@ -10,11 +10,11 @@ android {
compileSdk 34
defaultConfig {
applicationId "org.joinmastodon.android"
applicationId "org.joinmastodon.android.moshinda"
minSdk 23
targetSdk 34
versionCode 112
versionName "2.6.1"
versionCode 107
versionName "2.9.1+fork.107.moshinda"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -27,16 +27,16 @@ android {
debug{
debuggable true
}
appcenterPrivateBeta{
initWith release
minifyEnabled false
shrinkResources false
versionNameSuffix "-priv-beta"
}
appcenterPublicBeta{
initWith release
versionNameSuffix "-beta"
}
// appcenterPrivateBeta{
// initWith release
// minifyEnabled false
// shrinkResources false
// versionNameSuffix "-priv-beta"
// }
// appcenterPublicBeta{
// initWith release
// versionNameSuffix "-beta"
// }
githubRelease{
initWith release
}
@@ -50,12 +50,12 @@ android {
coreLibraryDesugaringEnabled true
}
sourceSets{
appcenterPrivateBeta{
setRoot "src/appcenter"
}
appcenterPublicBeta{
setRoot "src/appcenter"
}
// appcenterPrivateBeta{
// setRoot "src/appcenter"
// }
// appcenterPublicBeta{
// setRoot "src/appcenter"
// }
githubRelease{
setRoot "src/github"
}
@@ -90,7 +90,7 @@ dependencies {
implementation 'me.grishka.litex:viewpager:1.0.0'
implementation 'me.grishka.litex:viewpager2:1.0.0'
implementation 'me.grishka.litex:palette:1.0.0'
implementation 'me.grishka.appkit:appkit:1.3.0'
implementation 'me.grishka.appkit:appkit:1.4.4'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.squareup:otto:1.3.8'
@@ -101,11 +101,12 @@ dependencies {
annotationProcessor 'org.parceler:parceler:1.1.12'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
def appCenterSdkVersion = "5.0.4"
appcenterPrivateBetaImplementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"
appcenterPrivateBetaImplementation "com.microsoft.appcenter:appcenter-distribute:${appCenterSdkVersion}"
appcenterPublicBetaImplementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"
appcenterPublicBetaImplementation "com.microsoft.appcenter:appcenter-distribute:${appCenterSdkVersion}"
// MOSHIDON: we don't do that here
// def appCenterSdkVersion = "5.0.4"
// appcenterPrivateBetaImplementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"
// appcenterPrivateBetaImplementation "com.microsoft.appcenter:appcenter-distribute:${appCenterSdkVersion}"
// appcenterPublicBetaImplementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"
// appcenterPublicBetaImplementation "com.microsoft.appcenter:appcenter-distribute:${appCenterSdkVersion}"
androidTestImplementation 'androidx.test:core:1.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'

View File

@@ -35,6 +35,10 @@
*;
}
-keepnames public class org.joinmastodon.android.api.session.**{
*;
}
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
@com.squareup.otto.Subscribe <methods>;

View File

@@ -1,10 +1,8 @@
package org.joinmastodon.android.test;
import android.app.Instrumentation;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
@@ -14,7 +12,7 @@ import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.instance.GetInstance;
import org.joinmastodon.android.api.requests.instance.GetInstanceV2;
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
@@ -22,6 +20,7 @@ import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.fragments.onboarding.InstanceRulesFragment;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.InstanceV2;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.junit.Assert;
@@ -32,12 +31,9 @@ import org.parceler.Parcels;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeoutException;
import androidx.test.core.app.ActivityScenario;
import androidx.test.espresso.PerformException;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
@@ -47,19 +43,19 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.screenshot.ScreenCapture;
import androidx.test.runner.screenshot.Screenshot;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import okio.BufferedSink;
import okio.Okio;
import okio.Sink;
import okio.Source;
import static androidx.test.espresso.Espresso.*;
import static androidx.test.espresso.action.ViewActions.*;
import static androidx.test.espresso.assertion.ViewAssertions.*;
import static androidx.test.espresso.matcher.ViewMatchers.*;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.typeText;
import static androidx.test.espresso.matcher.ViewMatchers.Visibility;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
@RunWith(AndroidJUnit4.class)
@LargeTest
@@ -148,10 +144,10 @@ public class StoreScreenshotsGenerator{
takeScreenshot("Thread");
Instance[] _instance={null};
new GetInstance()
new GetInstanceV2()
.setCallback(new Callback<>(){
@Override
public void onSuccess(Instance result){
public void onSuccess(InstanceV2 result){
_instance[0]=result;
try{
barrier.await();

View File

@@ -23,7 +23,11 @@
</intent>
<intent>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="http"/>
<data android:scheme="http" android:host="*"/>
</intent>
<intent>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="https" android:host="*"/>
</intent>
</queries>

View File

@@ -0,0 +1,78 @@
package com.hootsuite.nachos;
import android.content.res.ColorStateList;
public class ChipConfiguration {
private final int mChipHorizontalSpacing;
private final ColorStateList mChipBackground;
private final int mChipCornerRadius;
private final int mChipTextColor;
private final int mChipTextSize;
private final int mChipHeight;
private final int mChipVerticalSpacing;
private final int mMaxAvailableWidth;
/**
* Creates a new ChipConfiguration. You can pass in {@code -1} or {@code null} for any of the parameters to indicate that parameter should be
* ignored.
*
* @param chipHorizontalSpacing the amount of horizontal space (in pixels) to put between consecutive chips
* @param chipBackground the {@link ColorStateList} to set as the background of the chips
* @param chipCornerRadius the corner radius of the chip background, in pixels
* @param chipTextColor the color to set as the text color of the chips
* @param chipTextSize the font size (in pixels) to use for the text of the chips
* @param chipHeight the height (in pixels) of each chip
* @param chipVerticalSpacing the amount of vertical space (in pixels) to put between chips on consecutive lines
* @param maxAvailableWidth the maximum available with for a chip (the width of a full line of text in the text view)
*/
ChipConfiguration(int chipHorizontalSpacing,
ColorStateList chipBackground,
int chipCornerRadius,
int chipTextColor,
int chipTextSize,
int chipHeight,
int chipVerticalSpacing,
int maxAvailableWidth) {
mChipHorizontalSpacing = chipHorizontalSpacing;
mChipBackground = chipBackground;
mChipCornerRadius = chipCornerRadius;
mChipTextColor = chipTextColor;
mChipTextSize = chipTextSize;
mChipHeight = chipHeight;
mChipVerticalSpacing = chipVerticalSpacing;
mMaxAvailableWidth = maxAvailableWidth;
}
public int getChipHorizontalSpacing() {
return mChipHorizontalSpacing;
}
public ColorStateList getChipBackground() {
return mChipBackground;
}
public int getChipCornerRadius() {
return mChipCornerRadius;
}
public int getChipTextColor() {
return mChipTextColor;
}
public int getChipTextSize() {
return mChipTextSize;
}
public int getChipHeight() {
return mChipHeight;
}
public int getChipVerticalSpacing() {
return mChipVerticalSpacing;
}
public int getMaxAvailableWidth() {
return mMaxAvailableWidth;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
package com.hootsuite.nachos.chip;
import androidx.annotation.Nullable;
public interface Chip {
/**
* @return the text represented by this Chip
*/
CharSequence getText();
/**
* @return the data associated with this Chip or null if no data is associated with it
*/
@Nullable
Object getData();
/**
* @return the width of the Chip or -1 if the Chip hasn't been given the chance to calculate its width
*/
int getWidth();
/**
* Sets the UI state.
*
* @param stateSet one of the state constants in {@link android.view.View}
*/
void setState(int[] stateSet);
}

View File

@@ -0,0 +1,44 @@
package com.hootsuite.nachos.chip;
import android.content.Context;
import com.hootsuite.nachos.ChipConfiguration;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* Interface to allow the creation and configuration of chips
*
* @param <C> The type of {@link Chip} that the implementation will create/configure
*/
public interface ChipCreator<C extends Chip> {
/**
* Creates a chip from the given context and text. Use this method when creating a brand new chip from a piece of text.
*
* @param context the {@link Context} to use to initialize the chip
* @param text the text the Chip should represent
* @param data the data to associate with the Chip, or null to associate no data
* @return the created chip
*/
C createChip(@NonNull Context context, @NonNull CharSequence text, @Nullable Object data);
/**
* Creates a chip from the given context and existing chip. Use this method when recreating a chip from an existing one.
*
* @param context the {@link Context} to use to initialize the chip
* @param existingChip the chip that the created chip should be based on
* @return the created chip
*/
C createChip(@NonNull Context context, @NonNull C existingChip);
/**
* Applies the given {@link ChipConfiguration} to the given {@link Chip}. Use this method to customize the appearance/behavior of a chip before
* adding it to the text.
*
* @param chip the chip to configure
* @param chipConfiguration the configuration to apply to the chip
*/
void configureChip(@NonNull C chip, @NonNull ChipConfiguration chipConfiguration);
}

View File

@@ -0,0 +1,20 @@
package com.hootsuite.nachos.chip;
public class ChipInfo {
private final CharSequence mText;
private final Object mData;
public ChipInfo(CharSequence text, Object data) {
this.mText = text;
this.mData = data;
}
public CharSequence getText() {
return mText;
}
public Object getData() {
return mData;
}
}

View File

@@ -0,0 +1,510 @@
package com.hootsuite.nachos.chip;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.text.style.ImageSpan;
import org.joinmastodon.android.R;
import androidx.annotation.Dimension;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* A Span that displays text and an optional icon inside of a material design chip. The chip's dimensions, colors etc. can be extensively customized
* through the various setter methods available in this class.
* The basic structure of the chip is the following:
* For chips with the icon on right:
* <pre>
*
* (chip vertical spacing / 2)
* ----------------------------------------------------------
* | |
* (left margin) | (padding edge) text (padding between image) icon | (right margin)
* | |
* ----------------------------------------------------------
* (chip vertical spacing / 2)
*
* </pre>
* For chips with the icon on the left (see {@link #setShowIconOnLeft(boolean)}):
* <pre>
*
* (chip vertical spacing / 2)
* ----------------------------------------------------------
* | |
* (left margin) | icon (padding between image) text (padding edge) | (right margin)
* | |
* ----------------------------------------------------------
* (chip vertical spacing / 2)
* </pre>
*/
public class ChipSpan extends ImageSpan implements Chip {
private static final float SCALE_PERCENT_OF_CHIP_HEIGHT = 0.70f;
private static final boolean ICON_ON_LEFT_DEFAULT = true;
private int[] mStateSet = new int[]{};
private String mEllipsis;
private ColorStateList mDefaultBackgroundColor;
private ColorStateList mBackgroundColor;
private int mTextColor;
private int mCornerRadius = -1;
private int mIconBackgroundColor;
private int mTextSize = -1;
private int mPaddingEdgePx;
private int mPaddingBetweenImagePx;
private int mLeftMarginPx;
private int mRightMarginPx;
private int mMaxAvailableWidth = -1;
private CharSequence mText;
private String mTextToDraw;
private Drawable mIcon;
private boolean mShowIconOnLeft = ICON_ON_LEFT_DEFAULT;
private int mChipVerticalSpacing = 0;
private int mChipHeight = -1;
private int mChipWidth = -1;
private int mIconWidth;
private int mCachedSize = -1;
private Object mData;
/**
* Constructs a new ChipSpan.
*
* @param context a {@link Context} that will be used to retrieve default configurations from resource files
* @param text the text for the ChipSpan to display
* @param icon an optional icon (can be {@code null}) for the ChipSpan to display
*/
public ChipSpan(@NonNull Context context, @NonNull CharSequence text, @Nullable Drawable icon, Object data) {
super(icon);
mIcon = icon;
mText = text;
mTextToDraw = mText.toString();
mEllipsis = context.getString(R.string.chip_ellipsis);
mDefaultBackgroundColor = context.getColorStateList(R.color.chip_material_background);
mBackgroundColor = mDefaultBackgroundColor;
mTextColor = context.getColor(R.color.chip_default_text_color);
mIconBackgroundColor = context.getColor(R.color.chip_default_icon_background_color);
Resources resources = context.getResources();
mPaddingEdgePx = resources.getDimensionPixelSize(R.dimen.chip_default_padding_edge);
mPaddingBetweenImagePx = resources.getDimensionPixelSize(R.dimen.chip_default_padding_between_image);
mLeftMarginPx = resources.getDimensionPixelSize(R.dimen.chip_default_left_margin);
mRightMarginPx = resources.getDimensionPixelSize(R.dimen.chip_default_right_margin);
mData = data;
}
/**
* Copy constructor to recreate a ChipSpan from an existing one
*
* @param context a {@link Context} that will be used to retrieve default configurations from resource files
* @param chipSpan the ChipSpan to copy
*/
public ChipSpan(@NonNull Context context, @NonNull ChipSpan chipSpan) {
this(context, chipSpan.getText(), chipSpan.getDrawable(), chipSpan.getData());
mDefaultBackgroundColor = chipSpan.mDefaultBackgroundColor;
mTextColor = chipSpan.mTextColor;
mIconBackgroundColor = chipSpan.mIconBackgroundColor;
mCornerRadius = chipSpan.mCornerRadius;
mTextSize = chipSpan.mTextSize;
mPaddingEdgePx = chipSpan.mPaddingEdgePx;
mPaddingBetweenImagePx = chipSpan.mPaddingBetweenImagePx;
mLeftMarginPx = chipSpan.mLeftMarginPx;
mRightMarginPx = chipSpan.mRightMarginPx;
mMaxAvailableWidth = chipSpan.mMaxAvailableWidth;
mShowIconOnLeft = chipSpan.mShowIconOnLeft;
mChipVerticalSpacing = chipSpan.mChipVerticalSpacing;
mChipHeight = chipSpan.mChipHeight;
mStateSet = chipSpan.mStateSet;
}
@Override
public Object getData() {
return mData;
}
/**
* Sets the height of the chip. This height should not include any extra spacing (for extra vertical spacing call {@link #setChipVerticalSpacing(int)}).
* The background of the chip will fill the full height provided here. If this method is never called, the chip will have the height of one full line
* of text by default. If {@code -1} is passed here, the chip will revert to this default behavior.
*
* @param chipHeight the height to set in pixels
*/
public void setChipHeight(int chipHeight) {
mChipHeight = chipHeight;
}
/**
* Sets the vertical spacing to include in between chips. Half of the value set here will be placed as empty space above the chip and half the value
* will be placed as empty space below the chip. Therefore chips on consecutive lines will have the full value as vertical space in between them.
* This spacing is achieved by adjusting the font metrics used by the text view containing these chips; however it does not come into effect until
* at least one chip is created. Note that vertical spacing is dependent on having a fixed chip height (set in {@link #setChipHeight(int)}). If a
* height is not specified in that method, the value set here will be ignored.
*
* @param chipVerticalSpacing the vertical spacing to set in pixels
*/
public void setChipVerticalSpacing(int chipVerticalSpacing) {
mChipVerticalSpacing = chipVerticalSpacing;
}
/**
* Sets the font size for the chip's text. If this method is never called, the chip text will have the same font size as the text in the TextView
* containing this chip by default. If {@code -1} is passed here, the chip will revert to this default behavior.
*
* @param size the font size to set in pixels
*/
public void setTextSize(int size) {
mTextSize = size;
invalidateCachedSize();
}
/**
* Sets the color for the chip's text.
*
* @param color the color to set (as a hexadecimal number in the form 0xAARRGGBB)
*/
public void setTextColor(int color) {
mTextColor = color;
}
/**
* Sets where the icon (if an icon was provided in the constructor) will appear.
*
* @param showIconOnLeft if true, the icon will appear on the left, otherwise the icon will appear on the right
*/
public void setShowIconOnLeft(boolean showIconOnLeft) {
this.mShowIconOnLeft = showIconOnLeft;
invalidateCachedSize();
}
/**
* Sets the left margin. This margin will appear as empty space (it will not share the chip's background color) to the left of the chip.
*
* @param leftMarginPx the left margin to set in pixels
*/
public void setLeftMargin(int leftMarginPx) {
mLeftMarginPx = leftMarginPx;
invalidateCachedSize();
}
/**
* Sets the right margin. This margin will appear as empty space (it will not share the chip's background color) to the right of the chip.
*
* @param rightMarginPx the right margin to set in pixels
*/
public void setRightMargin(int rightMarginPx) {
this.mRightMarginPx = rightMarginPx;
invalidateCachedSize();
}
/**
* Sets the background color. To configure which color in the {@link ColorStateList} is shown you can call {@link #setState(int[])}.
* Passing {@code null} here will cause the chip to revert to it's default background.
*
* @param backgroundColor a {@link ColorStateList} containing backgrounds for different states.
* @see #setState(int[])
*/
public void setBackgroundColor(@Nullable ColorStateList backgroundColor) {
mBackgroundColor = backgroundColor != null ? backgroundColor : mDefaultBackgroundColor;
}
/**
* Sets the chip background corner radius.
*
* @param cornerRadius The corner radius value, in pixels.
*/
public void setCornerRadius(@Dimension int cornerRadius) {
mCornerRadius = cornerRadius;
}
/**
* Sets the icon background color. This is the color of the circle that gets drawn behind the icon passed to the
* {@link #ChipSpan(Context, CharSequence, Drawable, Object)} constructor}
*
* @param iconBackgroundColor the icon background color to set (as a hexadecimal number in the form 0xAARRGGBB)
*/
public void setIconBackgroundColor(int iconBackgroundColor) {
mIconBackgroundColor = iconBackgroundColor;
}
public void setMaxAvailableWidth(int maxAvailableWidth) {
mMaxAvailableWidth = maxAvailableWidth;
invalidateCachedSize();
}
/**
* Sets the UI state. This state will be reflected in the background color drawn for the chip.
*
* @param stateSet one of the state constants in {@link android.view.View}
* @see #setBackgroundColor(ColorStateList)
*/
@Override
public void setState(int[] stateSet) {
this.mStateSet = stateSet != null ? stateSet : new int[]{};
}
@Override
public CharSequence getText() {
return mText;
}
@Override
public int getWidth() {
// If we haven't actually calculated a chip width yet just return -1, otherwise return the chip width + margins
return mChipWidth != -1 ? (mLeftMarginPx + mChipWidth + mRightMarginPx) : -1;
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
boolean usingFontMetrics = (fm != null);
// Adjust the font metrics regardless of whether or not there is a cached size so that the text view can maintain its height
if (usingFontMetrics) {
adjustFontMetrics(paint, fm);
}
if (mCachedSize == -1 && usingFontMetrics) {
mIconWidth = (mIcon != null) ? calculateChipHeight(fm.top, fm.bottom) : 0;
int actualWidth = calculateActualWidth(paint);
mCachedSize = actualWidth;
if (mMaxAvailableWidth != -1) {
int maxAvailableWidthMinusMargins = mMaxAvailableWidth - mLeftMarginPx - mRightMarginPx;
if (actualWidth > maxAvailableWidthMinusMargins) {
mTextToDraw = mText + mEllipsis;
while ((calculateActualWidth(paint) > maxAvailableWidthMinusMargins) && mTextToDraw.length() > 0) {
int lastCharacterIndex = mTextToDraw.length() - mEllipsis.length() - 1;
if (lastCharacterIndex < 0) {
break;
}
mTextToDraw = mTextToDraw.substring(0, lastCharacterIndex) + mEllipsis;
}
// Avoid a negative width
mChipWidth = Math.max(0, maxAvailableWidthMinusMargins);
mCachedSize = mMaxAvailableWidth;
}
}
}
return mCachedSize;
}
private int calculateActualWidth(Paint paint) {
// Only change the text size if a text size was set
if (mTextSize != -1) {
paint.setTextSize(mTextSize);
}
int totalPadding = mPaddingEdgePx;
// Find text width
Rect bounds = new Rect();
paint.getTextBounds(mTextToDraw, 0, mTextToDraw.length(), bounds);
int textWidth = bounds.width();
if (mIcon != null) {
totalPadding += mPaddingBetweenImagePx;
} else {
totalPadding += mPaddingEdgePx;
}
mChipWidth = totalPadding + textWidth + mIconWidth;
return getWidth();
}
public void invalidateCachedSize() {
mCachedSize = -1;
}
/**
* Adjusts the provided font metrics to make it seem like the font takes up {@code mChipHeight + mChipVerticalSpacing} pixels in height.
* This effectively ensures that the TextView will have a height equal to {@code mChipHeight + mChipVerticalSpacing} + whatever padding it has set.
* In {@link #draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)} the chip itself is drawn to that it is vertically centered with
* {@code mChipVerticalSpacing / 2} pixels of space above and below it
*
* @param paint the paint whose font metrics should be adjusted
* @param fm the font metrics object to populate through {@link Paint#getFontMetricsInt(Paint.FontMetricsInt)}
*/
private void adjustFontMetrics(Paint paint, Paint.FontMetricsInt fm) {
// Only actually adjust font metrics if we have a chip height set
if (mChipHeight != -1) {
paint.getFontMetricsInt(fm);
int textHeight = fm.descent - fm.ascent;
// Break up the vertical spacing in half because half will go above the chip, half will go below the chip
int halfSpacing = mChipVerticalSpacing / 2;
// Given that the text is centered vertically within the chip, the amount of space above or below the text (inbetween the text and chip)
// is half their difference in height:
int spaceBetweenChipAndText = (mChipHeight - textHeight) / 2;
int textTop = fm.top;
int chipTop = fm.top - spaceBetweenChipAndText;
int textBottom = fm.bottom;
int chipBottom = fm.bottom + spaceBetweenChipAndText;
// The text may have been taller to begin with so we take the most negative coordinate (highest up) to be the top of the content
int topOfContent = Math.min(textTop, chipTop);
// Same as above but we want the largest positive coordinate (lowest down) to be the bottom of the content
int bottomOfContent = Math.max(textBottom, chipBottom);
// Shift the top up by halfSpacing and the bottom down by halfSpacing
int topOfContentWithSpacing = topOfContent - halfSpacing;
int bottomOfContentWithSpacing = bottomOfContent + halfSpacing;
// Change the font metrics so that the TextView thinks the font takes up the vertical space of a chip + spacing
fm.ascent = topOfContentWithSpacing;
fm.descent = bottomOfContentWithSpacing;
fm.top = topOfContentWithSpacing;
fm.bottom = bottomOfContentWithSpacing;
}
}
private int calculateChipHeight(int top, int bottom) {
// If a chip height was set we can return that, otherwise calculate it from top and bottom
return mChipHeight != -1 ? mChipHeight : bottom - top;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
// Shift everything mLeftMarginPx to the left to create an empty space on the left (creating the margin)
x += mLeftMarginPx;
if (mChipHeight != -1) {
// If we set a chip height, adjust to vertically center chip in the line
// Adding (bottom - top) / 2 shifts the chip down so the top of it will be centered vertically
// Subtracting (mChipHeight / 2) shifts the chip back up so that the center of it will be centered vertically (as desired)
top += ((bottom - top) / 2) - (mChipHeight / 2);
bottom = top + mChipHeight;
}
// Perform actual drawing
drawBackground(canvas, x, top, bottom, paint);
drawText(canvas, x, top, bottom, paint, mTextToDraw);
if (mIcon != null) {
drawIcon(canvas, x, top, bottom, paint);
}
}
private void drawBackground(Canvas canvas, float x, int top, int bottom, Paint paint) {
int backgroundColor = mBackgroundColor.getColorForState(mStateSet, mBackgroundColor.getDefaultColor());
paint.setColor(backgroundColor);
int height = calculateChipHeight(top, bottom);
RectF rect = new RectF(x, top, x + mChipWidth, bottom);
int cornerRadius = (mCornerRadius != -1) ? mCornerRadius : height / 2;
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint);
paint.setColor(mTextColor);
}
private void drawText(Canvas canvas, float x, int top, int bottom, Paint paint, CharSequence text) {
if (mTextSize != -1) {
paint.setTextSize(mTextSize);
}
int height = calculateChipHeight(top, bottom);
Paint.FontMetrics fm = paint.getFontMetrics();
// The top value provided here is the y coordinate for the very top of the chip
// The y coordinate we are calculating is where the baseline of the text will be drawn
// Our objective is to have the midpoint between the top and baseline of the text be in line with the vertical center of the chip
// First we add height / 2 which will put the baseline at the vertical center of the chip
// Then we add half the height of the text which will lower baseline so that the midpoint is at the vertical center of the chip as desired
float adjustedY = top + ((height / 2) + ((-fm.top - fm.bottom) / 2));
// The x coordinate provided here is the left-most edge of the chip
// If there is no icon or the icon is on the right, then the text will start at the left-most edge, but indented with the edge padding, so we
// add mPaddingEdgePx
// If there is an icon and it's on the left, the text will start at the left-most edge, but indented by the combined width of the icon and
// the padding between the icon and text, so we add (mIconWidth + mPaddingBetweenImagePx)
float adjustedX = x + ((mIcon == null || !mShowIconOnLeft) ? mPaddingEdgePx : (mIconWidth + mPaddingBetweenImagePx));
canvas.drawText(text, 0, text.length(), adjustedX, adjustedY, paint);
}
private void drawIcon(Canvas canvas, float x, int top, int bottom, Paint paint) {
drawIconBackground(canvas, x, top, bottom, paint);
drawIconBitmap(canvas, x, top, bottom, paint);
}
private void drawIconBackground(Canvas canvas, float x, int top, int bottom, Paint paint) {
int height = calculateChipHeight(top, bottom);
paint.setColor(mIconBackgroundColor);
// Since it's a circle the diameter is equal to the height, so the radius == diameter / 2 == height / 2
int radius = height / 2;
// The coordinates that get passed to drawCircle are for the center of the circle
// x is the left edge of the chip, (x + mChipWidth) is the right edge of the chip
// So the center of the circle is one radius distance from either the left or right edge (depending on which side the icon is being drawn on)
float circleX = mShowIconOnLeft ? (x + radius) : (x + mChipWidth - radius);
// The y coordinate is always just one radius distance from the top
canvas.drawCircle(circleX, top + radius, radius, paint);
paint.setColor(mTextColor);
}
private void drawIconBitmap(Canvas canvas, float x, int top, int bottom, Paint paint) {
int height = calculateChipHeight(top, bottom);
// Create a scaled down version of the bitmap to fit within the circle (whose diameter == height)
Bitmap iconBitmap = Bitmap.createBitmap(mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Bitmap scaledIconBitMap = scaleDown(iconBitmap, (float) height * SCALE_PERCENT_OF_CHIP_HEIGHT, true);
iconBitmap.recycle();
Canvas bitmapCanvas = new Canvas(scaledIconBitMap);
mIcon.setBounds(0, 0, bitmapCanvas.getWidth(), bitmapCanvas.getHeight());
mIcon.draw(bitmapCanvas);
// We are drawing a square icon inside of a circle
// The coordinates we pass to canvas.drawBitmap have to be for the top-left corner of the bitmap
// The bitmap should be inset by half of (circle width - bitmap width)
// Since it's a circle, the circle's width is equal to it's height which is equal to the chip height
float xInsetWithinCircle = (height - bitmapCanvas.getWidth()) / 2;
// The icon x coordinate is going to be insetWithinCircle pixels away from the left edge of the circle
// If the icon is on the left, the left edge of the circle is just x
// If the icon is on the right, the left edge of the circle is x + mChipWidth - height
float iconX = mShowIconOnLeft ? (x + xInsetWithinCircle) : (x + mChipWidth - height + xInsetWithinCircle);
// The y coordinate works the same way (only it's always from the top edge)
float yInsetWithinCircle = (height - bitmapCanvas.getHeight()) / 2;
float iconY = top + yInsetWithinCircle;
canvas.drawBitmap(scaledIconBitMap, iconX, iconY, paint);
}
private Bitmap scaleDown(Bitmap realImage, float maxImageSize, boolean filter) {
float ratio = Math.min(maxImageSize / realImage.getWidth(), maxImageSize / realImage.getHeight());
int width = Math.round(ratio * realImage.getWidth());
int height = Math.round(ratio * realImage.getHeight());
return Bitmap.createScaledBitmap(realImage, width, height, filter);
}
@Override
public String toString() {
return mText.toString();
}
}

View File

@@ -0,0 +1,60 @@
package com.hootsuite.nachos.chip;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import com.hootsuite.nachos.ChipConfiguration;
import androidx.annotation.NonNull;
public class ChipSpanChipCreator implements ChipCreator<ChipSpan> {
@Override
public ChipSpan createChip(@NonNull Context context, @NonNull CharSequence text, Object data) {
return new ChipSpan(context, text, null, data);
}
@Override
public ChipSpan createChip(@NonNull Context context, @NonNull ChipSpan existingChip) {
return new ChipSpan(context, existingChip);
}
@Override
public void configureChip(@NonNull ChipSpan chip, @NonNull ChipConfiguration chipConfiguration) {
int chipHorizontalSpacing = chipConfiguration.getChipHorizontalSpacing();
ColorStateList chipBackground = chipConfiguration.getChipBackground();
int chipCornerRadius = chipConfiguration.getChipCornerRadius();
int chipTextColor = chipConfiguration.getChipTextColor();
int chipTextSize = chipConfiguration.getChipTextSize();
int chipHeight = chipConfiguration.getChipHeight();
int chipVerticalSpacing = chipConfiguration.getChipVerticalSpacing();
int maxAvailableWidth = chipConfiguration.getMaxAvailableWidth();
if (chipHorizontalSpacing != -1) {
chip.setLeftMargin(chipHorizontalSpacing / 2);
chip.setRightMargin(chipHorizontalSpacing / 2);
}
if (chipBackground != null) {
chip.setBackgroundColor(chipBackground);
}
if (chipCornerRadius != -1) {
chip.setCornerRadius(chipCornerRadius);
}
if (chipTextColor != Color.TRANSPARENT) {
chip.setTextColor(chipTextColor);
}
if (chipTextSize != -1) {
chip.setTextSize(chipTextSize);
}
if (chipHeight != -1) {
chip.setChipHeight(chipHeight);
}
if (chipVerticalSpacing != -1) {
chip.setChipVerticalSpacing(chipVerticalSpacing);
}
if (maxAvailableWidth != -1) {
chip.setMaxAvailableWidth(maxAvailableWidth);
}
}
}

View File

@@ -0,0 +1,95 @@
package com.hootsuite.nachos.terminator;
import android.text.Editable;
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* This interface is used to handle the management of characters that should trigger the creation of chips in a text view.
*
* @see ChipTokenizer
*/
public interface ChipTerminatorHandler {
/**
* When a chip terminator character is encountered in newly inserted text, all tokens in the whole text view will be chipified
*/
int BEHAVIOR_CHIPIFY_ALL = 0;
/**
* When a chip terminator character is encountered in newly inserted text, only the current token (that in which the chip terminator character
* was found) will be chipified. This token may extend beyond where the chip terminator character was located.
*/
int BEHAVIOR_CHIPIFY_CURRENT_TOKEN = 1;
/**
* When a chip terminator character is encountered in newly inserted text, only the text from the previous chip up until the chip terminator
* character will be chipified. This may not be an entire token.
*/
int BEHAVIOR_CHIPIFY_TO_TERMINATOR = 2;
/**
* Constant for use with {@link #setPasteBehavior(int)}. Use this if a paste should behave the same as a standard text input (the chip temrinators
* will all behave according to their pre-determined behavior set through {@link #addChipTerminator(char, int)} or {@link #setChipTerminators(Map)}).
*/
int PASTE_BEHAVIOR_USE_DEFAULT = -1;
/**
* Sets all the characters that will be marked as chip terminators. This will replace any previously set chip terminators.
*
* @param chipTerminators a map of characters to be marked as chip terminators to behaviors that describe how to respond to the characters, or null
* to remove all chip terminators
*/
void setChipTerminators(@Nullable Map<Character, Integer> chipTerminators);
/**
* Adds a character as a chip terminator. When the provided character is encountered in entered text, the nearby text will be chipified according
* to the behavior provided here.
* {@code behavior} Must be one of:
* <ul>
* <li>{@link #BEHAVIOR_CHIPIFY_ALL}</li>
* <li>{@link #BEHAVIOR_CHIPIFY_CURRENT_TOKEN}</li>
* <li>{@link #BEHAVIOR_CHIPIFY_TO_TERMINATOR}</li>
* </ul>
*
* @param character the character to mark as a chip terminator
* @param behavior the behavior describing how to respond to the chip terminator
*/
void addChipTerminator(char character, int behavior);
/**
* Customizes the way paste events are handled.
* If one of:
* <ul>
* <li>{@link #BEHAVIOR_CHIPIFY_ALL}</li>
* <li>{@link #BEHAVIOR_CHIPIFY_CURRENT_TOKEN}</li>
* <li>{@link #BEHAVIOR_CHIPIFY_TO_TERMINATOR}</li>
* </ul>
* is passed, all chip terminators will be handled with that behavior when a paste event occurs.
* If {@link #PASTE_BEHAVIOR_USE_DEFAULT} is passed, whatever behavior is configured for a particular chip terminator
* (through {@link #setChipTerminators(Map)} or {@link #addChipTerminator(char, int)} will be used for that chip terminator
*
* @param pasteBehavior the behavior to use on a paste event
*/
void setPasteBehavior(int pasteBehavior);
/**
* Parses the provided text looking for characters marked as chip terminators through {@link #addChipTerminator(char, int)} and {@link #setChipTerminators(Map)}.
* The provided {@link Editable} will be modified if chip terminators are encountered.
*
* @param tokenizer the {@link ChipTokenizer} to use to identify and chipify tokens in the text
* @param text the text in which to search for chip terminators tokens to be chipped
* @param start the index at which to begin looking for chip terminators (inclusive)
* @param end the index at which to end looking for chip terminators (exclusive)
* @param isPasteEvent true if this handling is for a paste event in which case the behavior set in {@link #setPasteBehavior(int)} will be used,
* otherwise false
* @return an non-negative integer indicating the index where the cursor (selection) should be placed once the handling is complete,
* or a negative integer indicating that the cursor should not be moved.
*/
int findAndHandleChipTerminators(@NonNull ChipTokenizer tokenizer, @NonNull Editable text, int start, int end, boolean isPasteEvent);
}

View File

@@ -0,0 +1,115 @@
package com.hootsuite.nachos.terminator;
import android.text.Editable;
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
import java.util.HashMap;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class DefaultChipTerminatorHandler implements ChipTerminatorHandler {
@Nullable
private Map<Character, Integer> mChipTerminators;
private int mPasteBehavior = BEHAVIOR_CHIPIFY_TO_TERMINATOR;
@Override
public void setChipTerminators(@Nullable Map<Character, Integer> chipTerminators) {
mChipTerminators = chipTerminators;
}
@Override
public void addChipTerminator(char character, int behavior) {
if (mChipTerminators == null) {
mChipTerminators = new HashMap<>();
}
mChipTerminators.put(character, behavior);
}
@Override
public void setPasteBehavior(int pasteBehavior) {
mPasteBehavior = pasteBehavior;
}
@Override
public int findAndHandleChipTerminators(@NonNull ChipTokenizer tokenizer, @NonNull Editable text, int start, int end, boolean isPasteEvent) {
// If we don't have a tokenizer or any chip terminators, there's nothing to look for
if (mChipTerminators == null) {
return -1;
}
TextIterator textIterator = new TextIterator(text, start, end);
int selectionIndex = -1;
characterLoop:
while (textIterator.hasNextCharacter()) {
char theChar = textIterator.nextCharacter();
if (isChipTerminator(theChar)) {
int behavior = (isPasteEvent && mPasteBehavior != PASTE_BEHAVIOR_USE_DEFAULT) ? mPasteBehavior : mChipTerminators.get(theChar);
int newSelection = -1;
switch (behavior) {
case BEHAVIOR_CHIPIFY_ALL:
selectionIndex = handleChipifyAll(textIterator, tokenizer);
break characterLoop;
case BEHAVIOR_CHIPIFY_CURRENT_TOKEN:
newSelection = handleChipifyCurrentToken(textIterator, tokenizer);
break;
case BEHAVIOR_CHIPIFY_TO_TERMINATOR:
newSelection = handleChipifyToTerminator(textIterator, tokenizer);
break;
}
if (newSelection != -1) {
selectionIndex = newSelection;
}
}
}
return selectionIndex;
}
private int handleChipifyAll(TextIterator textIterator, ChipTokenizer tokenizer) {
textIterator.deleteCharacter(true);
tokenizer.terminateAllTokens(textIterator.getText());
return textIterator.totalLength();
}
private int handleChipifyCurrentToken(TextIterator textIterator, ChipTokenizer tokenizer) {
textIterator.deleteCharacter(true);
Editable text = textIterator.getText();
int index = textIterator.getIndex();
int tokenStart = tokenizer.findTokenStart(text, index);
int tokenEnd = tokenizer.findTokenEnd(text, index);
if (tokenStart < tokenEnd) {
CharSequence chippedText = tokenizer.terminateToken(text.subSequence(tokenStart, tokenEnd), null);
textIterator.replace(tokenStart, tokenEnd, chippedText);
return tokenStart + chippedText.length();
}
return -1;
}
private int handleChipifyToTerminator(TextIterator textIterator, ChipTokenizer tokenizer) {
Editable text = textIterator.getText();
int index = textIterator.getIndex();
if (index > 0) {
int tokenStart = tokenizer.findTokenStart(text, index);
if (tokenStart < index) {
CharSequence chippedText = tokenizer.terminateToken(text.subSequence(tokenStart, index), null);
textIterator.replace(tokenStart, index + 1, chippedText);
} else {
textIterator.deleteCharacter(false);
}
} else {
textIterator.deleteCharacter(false);
}
return -1;
}
private boolean isChipTerminator(char character) {
return mChipTerminators != null && mChipTerminators.keySet().contains(character);
}
}

View File

@@ -0,0 +1,63 @@
package com.hootsuite.nachos.terminator;
import android.text.Editable;
public class TextIterator {
private Editable mText;
private int mStart;
private int mEnd;
private int mIndex;
public TextIterator(Editable text, int start, int end) {
mText = text;
mStart = start;
mEnd = end;
mIndex = mStart - 1; // Subtract 1 so that the first call to nextCharacter() will return the first character
}
public int totalLength() {
return mText.length();
}
public int windowLength() {
return mEnd - mStart;
}
public Editable getText() {
return mText;
}
public int getIndex() {
return mIndex;
}
public boolean hasNextCharacter() {
return (mIndex + 1) < mEnd;
}
public char nextCharacter() {
mIndex++;
return mText.charAt(mIndex);
}
public void deleteCharacter(boolean maintainIndex) {
mText.replace(mIndex, mIndex + 1, "");
if (!maintainIndex) {
mIndex--;
}
mEnd--;
}
public void replace(int replaceStart, int replaceEnd, CharSequence chippedText) {
mText.replace(replaceStart, replaceEnd, chippedText);
// Update indexes
int newLength = chippedText.length();
int oldLength = replaceEnd - replaceStart;
mIndex = replaceStart + newLength - 1;
mEnd += newLength - oldLength;
}
}

View File

@@ -0,0 +1,89 @@
package com.hootsuite.nachos.tokenizer;
import android.text.Editable;
import android.text.Spanned;
import android.util.Pair;
import com.hootsuite.nachos.ChipConfiguration;
import com.hootsuite.nachos.chip.Chip;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* Base implementation of the {@link ChipTokenizer} interface that performs no actions and returns default values.
* This class allows for the easy creation of a ChipTokenizer that only implements some of the methods of the interface.
*/
public abstract class BaseChipTokenizer implements ChipTokenizer {
@Override
public void applyConfiguration(Editable text, ChipConfiguration chipConfiguration) {
// Do nothing
}
@Override
public int findTokenStart(CharSequence charSequence, int i) {
// Do nothing
return 0;
}
@Override
public int findTokenEnd(CharSequence charSequence, int i) {
// Do nothing
return 0;
}
@NonNull
@Override
public List<Pair<Integer, Integer>> findAllTokens(CharSequence text) {
// Do nothing
return new ArrayList<>();
}
@Override
public CharSequence terminateToken(CharSequence charSequence, @Nullable Object data) {
// Do nothing
return charSequence;
}
@Override
public void terminateAllTokens(Editable text) {
// Do nothing
}
@Override
public int findChipStart(Chip chip, Spanned text) {
// Do nothing
return 0;
}
@Override
public int findChipEnd(Chip chip, Spanned text) {
// Do nothing
return 0;
}
@NonNull
@Override
public Chip[] findAllChips(int start, int end, Spanned text) {
return new Chip[]{};
}
@Override
public void revertChipToToken(Chip chip, Editable text) {
// Do nothing
}
@Override
public void deleteChip(Chip chip, Editable text) {
// Do nothing
}
@Override
public void deleteChipAndPadding(Chip chip, Editable text) {
// Do nothing
}
}

View File

@@ -0,0 +1,134 @@
package com.hootsuite.nachos.tokenizer;
import android.text.Editable;
import android.text.Spanned;
import android.util.Pair;
import com.hootsuite.nachos.ChipConfiguration;
import com.hootsuite.nachos.chip.Chip;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* An extension of {@link android.widget.MultiAutoCompleteTextView.Tokenizer Tokenizer} that provides extra support
* for chipification.
* <p>
* In the context of this interface, a token is considered to be plain (non-chipped) text. Once a token is terminated it becomes or contains a chip.
* </p>
* <p>
* The CharSequences passed to the ChipTokenizer methods may contain both chipped text
* and plain text so the tokenizer must have some method of distinguishing between the two (e.g. using a delimeter character.
* The {@link #terminateToken(CharSequence, Object)} method is where a chip can be formed and returned to replace the plain text.
* Whatever class the implementation deems to represent a chip, must implement the {@link Chip} interface.
* </p>
*
* @see SpanChipTokenizer
*/
public interface ChipTokenizer {
/**
* Configures this ChipTokenizer to produce chips with the provided attributes. For each of these attributes, {@code -1} or {@code null} may be
* passed to indicate that the attribute may be ignored.
* <p>
* This will also apply the provided {@link ChipConfiguration} to any existing chips in the provided text.
* </p>
*
* @param text the text in which to search for existing chips to apply the configuration to
* @param chipConfiguration a {@link ChipConfiguration} containing customizations for the chips produced by this class
*/
void applyConfiguration(Editable text, ChipConfiguration chipConfiguration);
/**
* Returns the start of the token that ends at offset
* <code>cursor</code> within <code>text</code>.
*/
int findTokenStart(CharSequence text, int cursor);
/**
* Returns the end of the token (minus trailing punctuation)
* that begins at offset <code>cursor</code> within <code>text</code>.
*/
int findTokenEnd(CharSequence text, int cursor);
/**
* Searches through {@code text} for any tokens.
*
* @param text the text in which to search for un-terminated tokens
* @return a list of {@link Pair}s of the form (startIndex, endIndex) containing the locations of all
* unterminated tokens
*/
@NonNull
List<Pair<Integer, Integer>> findAllTokens(CharSequence text);
/**
* Returns <code>text</code>, modified, if necessary, to ensure that
* it ends with a token terminator (for example a space or comma).
*/
CharSequence terminateToken(CharSequence text, @Nullable Object data);
/**
* Terminates (converts from token into chip) all unterminated tokens in the provided text.
* This method CAN alter the provided text.
*
* @param text the text in which to terminate all tokens
*/
void terminateAllTokens(Editable text);
/**
* Finds the index of the first character in {@code text} that is a part of {@code chip}
*
* @param chip the chip whose start should be found
* @param text the text in which to search for the start of {@code chip}
* @return the start index of the chip
*/
int findChipStart(Chip chip, Spanned text);
/**
* Finds the index of the character after the last character in {@code text} that is a part of {@code chip}
*
* @param chip the chip whose end should be found
* @param text the text in which to search for the end of {@code chip}
* @return the end index of the chip
*/
int findChipEnd(Chip chip, Spanned text);
/**
* Searches through {@code text} for any chips
*
* @param start index to start looking for terminated tokens (inclusive)
* @param end index to end looking for terminated tokens (exclusive)
* @param text the text in which to search for terminated tokens
* @return a list of objects implementing the {@link Chip} interface to represent the terminated tokens
*/
@NonNull
Chip[] findAllChips(int start, int end, Spanned text);
/**
* Effectively does the opposite of {@link #terminateToken(CharSequence, Object)} by reverting the provided chip back into a token.
* This method CAN alter the provided text.
*
* @param chip the chip to revert into a token
* @param text the text in which the chip resides
*/
void revertChipToToken(Chip chip, Editable text);
/**
* Removes a chip and any text it encompasses from {@code text}. This method CAN alter the provided text.
*
* @param chip the chip to remove
* @param text the text to remove the chip from
*/
void deleteChip(Chip chip, Editable text);
/**
* Removes a chip, any text it encompasses AND any padding text (such as spaces) that may have been inserted when the chip was created in
* {@link #terminateToken(CharSequence, Object)} or after. This method CAN alter the provided text.
*
* @param chip the chip to remove
* @param text the text to remove the chip and padding from
*/
void deleteChipAndPadding(Chip chip, Editable text);
}

View File

@@ -0,0 +1,246 @@
package com.hootsuite.nachos.tokenizer;
import android.content.Context;
import android.text.Editable;
import android.text.SpannableString;
import android.text.Spanned;
import android.util.Pair;
import com.hootsuite.nachos.ChipConfiguration;
import com.hootsuite.nachos.chip.Chip;
import com.hootsuite.nachos.chip.ChipCreator;
import com.hootsuite.nachos.chip.ChipSpan;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* A default implementation of {@link ChipTokenizer}.
* This implementation does the following:
* <ul>
* <li>Surrounds each token with a space and the Unit Separator ASCII control character (31) - See the diagram below
* <ul>
* <li>The spaces are included so that android keyboards can distinguish the chips as different words and provide accurate
* autocorrect suggestions</li>
* </ul>
* </li>
* <li>Replaces each token with a {@link ChipSpan} containing the same text, once the token terminates</li>
* <li>Uses the values passed to {@link #applyConfiguration(Editable, ChipConfiguration)} to configure any ChipSpans that get created</li>
* </ul>
* Each terminated token will therefore look like the following (this is what will be returned from {@link #terminateToken(CharSequence, Object)}):
* <pre>
* -----------------------------------------------------------
* | SpannableString |
* | ---------------------------------------------------- |
* | | ChipSpan | |
* | | | |
* | | space separator text separator space | |
* | | | |
* | ---------------------------------------------------- |
* -----------------------------------------------------------
* </pre>
*
* @see ChipSpan
*/
public class SpanChipTokenizer<C extends Chip> implements ChipTokenizer {
/**
* The character used to separate chips internally is the US (Unit Separator) ASCII control character.
* This character is used because it's untypable so we have complete control over when chips are created.
*/
public static final char CHIP_SPAN_SEPARATOR = 31;
public static final char AUTOCORRECT_SEPARATOR = ' ';
private Context mContext;
@Nullable
private ChipConfiguration mChipConfiguration;
@NonNull
private ChipCreator<C> mChipCreator;
@NonNull
private Class<C> mChipClass;
private Comparator<Pair<Integer, Integer>> mReverseTokenIndexesSorter = new Comparator<Pair<Integer, Integer>>() {
@Override
public int compare(Pair<Integer, Integer> lhs, Pair<Integer, Integer> rhs) {
return rhs.first - lhs.first;
}
};
public SpanChipTokenizer(Context context, @NonNull ChipCreator<C> chipCreator, @NonNull Class<C> chipClass) {
mContext = context;
mChipCreator = chipCreator;
mChipClass = chipClass;
}
@Override
public void applyConfiguration(Editable text, ChipConfiguration chipConfiguration) {
mChipConfiguration = chipConfiguration;
for (C chip : findAllChips(0, text.length(), text)) {
// Recreate the chips with the new configuration
int chipStart = findChipStart(chip, text);
deleteChip(chip, text);
text.insert(chipStart, terminateToken(mChipCreator.createChip(mContext, chip)));
}
}
@Override
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
// Work backwards until we find a CHIP_SPAN_SEPARATOR
while (i > 0 && text.charAt(i - 1) != CHIP_SPAN_SEPARATOR) {
i--;
}
// Work forwards to skip over any extra whitespace at the beginning of the token
while (i > 0 && i < text.length() && Character.isWhitespace(text.charAt(i))) {
i++;
}
return i;
}
@Override
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
// Work forwards till we find a CHIP_SPAN_SEPARATOR
while (i < len) {
if (text.charAt(i) == CHIP_SPAN_SEPARATOR) {
return (i - 1); // subtract one because the CHIP_SPAN_SEPARATOR will be preceded by a space
} else {
i++;
}
}
return len;
}
@NonNull
@Override
public List<Pair<Integer, Integer>> findAllTokens(CharSequence text) {
List<Pair<Integer, Integer>> unterminatedTokens = new ArrayList<>();
boolean insideChip = false;
// Iterate backwards through the text (to avoid messing up indexes)
for (int index = text.length() - 1; index >= 0; index--) {
char theCharacter = text.charAt(index);
// Every time we hit a CHIP_SPAN_SEPARATOR character we switch from being inside to outside
// or outside to inside a chip
// This check must happen before the whitespace check because CHIP_SPAN_SEPARATOR is considered a whitespace character
if (theCharacter == CHIP_SPAN_SEPARATOR) {
insideChip = !insideChip;
continue;
}
// Completely skip over whitespace
if (Character.isWhitespace(theCharacter)) {
continue;
}
// If we're ever outside a chip, see if the text we're in is a viable token for chipification
if (!insideChip) {
int tokenStart = findTokenStart(text, index);
int tokenEnd = findTokenEnd(text, index);
// Can only actually be chipified if there's at least one character between them
if (tokenEnd - tokenStart >= 1) {
unterminatedTokens.add(new Pair<>(tokenStart, tokenEnd));
index = tokenStart;
}
}
}
return unterminatedTokens;
}
@Override
public CharSequence terminateToken(CharSequence text, @Nullable Object data) {
// Remove leading/trailing whitespace
CharSequence trimmedText = text.toString().trim();
return terminateToken(mChipCreator.createChip(mContext, trimmedText, data));
}
private CharSequence terminateToken(C chip) {
// Surround the text with CHIP_SPAN_SEPARATOR and spaces
// The spaces allow autocorrect to correctly identify words
String chipSeparator = Character.toString(CHIP_SPAN_SEPARATOR);
String autoCorrectSeparator = Character.toString(AUTOCORRECT_SEPARATOR);
CharSequence textWithSeparator = autoCorrectSeparator + chipSeparator + chip.getText() + chipSeparator + autoCorrectSeparator;
// Build the container object to house the ChipSpan and space
SpannableString spannableString = new SpannableString(textWithSeparator);
// Attach the ChipSpan
if (mChipConfiguration != null) {
mChipCreator.configureChip(chip, mChipConfiguration);
}
spannableString.setSpan(chip, 0, textWithSeparator.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableString;
}
@Override
public void terminateAllTokens(Editable text) {
List<Pair<Integer, Integer>> unterminatedTokens = findAllTokens(text);
// Sort in reverse order (so index changes don't affect anything)
Collections.sort(unterminatedTokens, mReverseTokenIndexesSorter);
for (Pair<Integer, Integer> indexes : unterminatedTokens) {
int start = indexes.first;
int end = indexes.second;
CharSequence textToChip = text.subSequence(start, end);
CharSequence chippedText = terminateToken(textToChip, null);
text.replace(start, end, chippedText);
}
}
@Override
public int findChipStart(Chip chip, Spanned text) {
return text.getSpanStart(chip);
}
@Override
public int findChipEnd(Chip chip, Spanned text) {
return text.getSpanEnd(chip);
}
@SuppressWarnings("unchecked")
@NonNull
@Override
public C[] findAllChips(int start, int end, Spanned text) {
C[] spansArray = text.getSpans(start, end, mChipClass);
return (spansArray != null) ? spansArray : (C[]) Array.newInstance(mChipClass, 0);
}
@Override
public void revertChipToToken(Chip chip, Editable text) {
int chipStart = findChipStart(chip, text);
int chipEnd = findChipEnd(chip, text);
text.removeSpan(chip);
text.replace(chipStart, chipEnd, chip.getText());
}
@Override
public void deleteChip(Chip chip, Editable text) {
int chipStart = findChipStart(chip, text);
int chipEnd = findChipEnd(chip, text);
text.removeSpan(chip);
// On the emulator for some reason the text automatically gets deleted and chipStart and chipEnd end up both being -1, so in that case we
// don't need to call text.delete(...)
if (chipStart != chipEnd) {
text.delete(chipStart, chipEnd);
}
}
@Override
public void deleteChipAndPadding(Chip chip, Editable text) {
// This implementation does not add any extra padding outside of the span so we can just delete the chip normally
deleteChip(chip, text);
}
}

View File

@@ -0,0 +1,32 @@
package com.hootsuite.nachos.validator;
import android.text.SpannableStringBuilder;
import android.util.Pair;
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
import java.util.List;
import androidx.annotation.NonNull;
/**
* A {@link NachoValidator} that deems text to be invalid if it contains
* unterminated tokens and fixes the text by chipifying all the unterminated tokens.
*/
public class ChipifyingNachoValidator implements NachoValidator {
@Override
public boolean isValid(@NonNull ChipTokenizer chipTokenizer, CharSequence text) {
// The text is considered valid if there are no unterminated tokens (everything is a chip)
List<Pair<Integer, Integer>> unterminatedTokens = chipTokenizer.findAllTokens(text);
return unterminatedTokens.isEmpty();
}
@Override
public CharSequence fixText(@NonNull ChipTokenizer chipTokenizer, CharSequence invalidText) {
SpannableStringBuilder newText = new SpannableStringBuilder(invalidText);
chipTokenizer.terminateAllTokens(newText);
return newText;
}
}

View File

@@ -0,0 +1,5 @@
package com.hootsuite.nachos.validator;
public interface IllegalCharacterIdentifier {
boolean isCharacterIllegal(Character c);
}

View File

@@ -0,0 +1,29 @@
package com.hootsuite.nachos.validator;
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
import androidx.annotation.NonNull;
/**
* Interface used to ensure that a given CharSequence complies to a particular format.
*/
public interface NachoValidator {
/**
* Validates the specified text.
*
* @return true If the text currently in the text editor is valid.
* @see #fixText(ChipTokenizer, CharSequence)
*/
boolean isValid(@NonNull ChipTokenizer chipTokenizer, CharSequence text);
/**
* Corrects the specified text to make it valid.
*
* @param invalidText A string that doesn't pass validation: isValid(invalidText)
* returns false
* @return A string based on invalidText such as invoking isValid() on it returns true.
* @see #isValid(ChipTokenizer, CharSequence)
*/
CharSequence fixText(@NonNull ChipTokenizer chipTokenizer, CharSequence invalidText);
}

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,70 @@
package org.joinmastodon.android;
import static org.joinmastodon.android.api.MastodonAPIController.gson;
import android.content.Context;
import android.content.SharedPreferences;
import com.google.gson.JsonSyntaxException;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import java.lang.reflect.Type;
public class GlobalUserPreferences{
public static boolean playGifs;
public static boolean useCustomTabs;
public static boolean altTextReminders, confirmUnfollow, confirmBoost, confirmDeletePost;
public static ThemePreference theme=ThemePreference.AUTO;
public static boolean useDynamicColors;
public static boolean showInteractionCounts;
public static boolean customEmojiInNames;
public static boolean showCWs;
public static boolean hideSensitiveMedia;
// MOSHIDON:
public static boolean trueBlackTheme;
public static boolean loadNewPosts;
public static boolean showNewPostsButton;
public static boolean toolbarMarquee;
public static boolean disableSwipe;
public static boolean enableDeleteNotifications;
public static boolean translateButtonOpenedOnly;
public static boolean uniformNotificationIcon;
public static boolean reduceMotion;
public static boolean showAltIndicator;
public static boolean showNoAltIndicator;
public static boolean enablePreReleases;
public static PrefixRepliesMode prefixReplies;
public static boolean collapseLongPosts;
public static boolean spectatorMode;
public static boolean autoHideFab;
public static boolean allowRemoteLoading;
public static AutoRevealMode autoRevealEqualSpoilers;
public static boolean disableM3PillActiveIndicator;
public static boolean showNavigationLabels;
public static boolean displayPronounsInTimelines, displayPronounsInThreads, displayPronounsInUserListings;
public static boolean overlayMedia;
public static boolean showSuicideHelp;
public static boolean underlinedLinks;
public static AccountLocalPreferences.ColorPreference color;
public static boolean likeIcon;
public static boolean showDividers;
public static boolean relocatePublishButton;
public static boolean defaultToUnlistedReplies;
public static boolean doubleTapToSearch;
public static boolean doubleTapToSwipe;
public static boolean confirmBeforeReblog;
public static boolean hapticFeedback;
public static boolean replyLineAboveHeader;
public static boolean swapBookmarkWithBoostAction;
public static boolean mentionRebloggerAutomatically;
public static boolean showPostsWithoutAlt;
public static boolean showMediaPreview;
public static boolean removeTrackingParams;
private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
@@ -29,6 +83,24 @@ public class GlobalUserPreferences{
confirmBoost=prefs.getBoolean("confirmBoost", false);
confirmDeletePost=prefs.getBoolean("confirmDeletePost", true);
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
useDynamicColors=prefs.getBoolean("useDynamicColors", true);
showInteractionCounts=prefs.getBoolean("interactionCounts", true);
customEmojiInNames=prefs.getBoolean("emojiInNames", true);
showCWs=prefs.getBoolean("showCWs", true);
hideSensitiveMedia=prefs.getBoolean("hideSensitive", true);
if(!prefs.getBoolean("perAccountMigrationDone", false)){
AccountSession account=AccountSessionManager.getInstance().getLastActiveAccount();
if(account!=null){
SharedPreferences accPrefs=account.getRawLocalPreferences();
showInteractionCounts=accPrefs.getBoolean("interactionCounts", true);
customEmojiInNames=accPrefs.getBoolean("emojiInNames", true);
showCWs=accPrefs.getBoolean("showCWs", true);
hideSensitiveMedia=accPrefs.getBoolean("hideSensitive", true);
save();
}
// Also applies to new app installs
prefs.edit().putBoolean("perAccountMigrationDone", true).apply();
}
}
public static void save(){
@@ -40,6 +112,11 @@ public class GlobalUserPreferences{
.putBoolean("confirmUnfollow", confirmUnfollow)
.putBoolean("confirmBoost", confirmBoost)
.putBoolean("confirmDeletePost", confirmDeletePost)
.putBoolean("useDynamicColors", useDynamicColors)
.putBoolean("interactionCounts", showInteractionCounts)
.putBoolean("emojiInNames", customEmojiInNames)
.putBoolean("showCWs", showCWs)
.putBoolean("hideSensitive", hideSensitiveMedia)
.apply();
}
@@ -81,4 +158,35 @@ public class GlobalUserPreferences{
OLD_POST,
NON_MUTUAL
}
// MOSHIDON:
public enum AutoRevealMode {
NEVER,
THREADS,
DISCUSSIONS
}
// MOSHIDON:
public enum PrefixRepliesMode {
NEVER,
ALWAYS,
TO_OTHERS
}
// MOSHIDON: we have jason
public static <T> T fromJson(String json, Type type, T orElse){
if(json==null) return orElse;
try{
T value=gson.fromJson(json, type);
return value==null ? orElse : value;
}catch(JsonSyntaxException ignored){
return orElse;
}
}
// MOSHIDON: enums too!
public static <T extends Enum<T>> T enumValue(Class<T> enumType, String name) {
try { return Enum.valueOf(enumType, name); }
catch (NullPointerException npe) { return null; }
}
}

View File

@@ -3,6 +3,7 @@ package org.joinmastodon.android;
import android.Manifest;
import android.app.Application;
import android.app.Fragment;
import android.app.assist.AssistContent;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
@@ -16,12 +17,14 @@ import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.requests.search.GetSearchResults;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.AssistContentProviderFragment;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.SplashFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.SearchResults;
import org.joinmastodon.android.ui.utils.UiUtils;
@@ -181,7 +184,7 @@ public class MainActivity extends FragmentStackActivity{
public void restartHomeFragment(){
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
showFragmentClearingBackStack(new SplashFragment());
showFragmentClearingBackStack(new CustomWelcomeFragment());
}else{
AccountSessionManager.getInstance().maybeUpdateLocalInfo();
AccountSession session;
@@ -229,4 +232,11 @@ public class MainActivity extends FragmentStackActivity{
return null;
return getFragmentManager().findFragmentById(fragmentContainers.get(fragmentContainers.size()-1).getId());
}
@Override
public void onProvideAssistContent(AssistContent outContent){
if(getTopmostFragment() instanceof AssistContentProviderFragment provider){
provider.onProvideAssistContent(outContent);
}
}
}

View File

@@ -6,7 +6,6 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
@@ -79,7 +78,7 @@ public class OAuthActivity extends Activity{
progress.dismiss();
}
})
.exec(instance.uri, token);
.exec(instance.getDomain(), token);
}
@Override
@@ -88,7 +87,7 @@ public class OAuthActivity extends Activity{
progress.dismiss();
}
})
.execNoAuth(instance.uri);
.execNoAuth(instance.getDomain());
}
private void handleError(ErrorResponse error){

View File

@@ -23,6 +23,7 @@ import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Mention;
import org.joinmastodon.android.model.NotificationType;
import org.joinmastodon.android.model.PushNotification;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.utils.UiUtils;
@@ -36,6 +37,8 @@ import java.util.stream.Collectors;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.imageloader.ImageCache;
import me.grishka.appkit.imageloader.ImageLoaderCallback;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.V;
@@ -103,12 +106,31 @@ public class PushNotificationReceiver extends BroadcastReceiver{
}
private void notify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification){
if(TextUtils.isEmpty(pn.icon)){
doNotify(context, pn, accountID, notification, null);
}else{
ImageCache.getInstance(context).get(new UrlImageLoaderRequest(pn.icon, V.dp(50), V.dp(50)), null, new ImageLoaderCallback(){
@Override
public void onImageLoaded(ImageLoaderRequest req, Drawable image){
doNotify(context, pn, accountID, notification, image);
}
@Override
public void onImageLoadingFailed(ImageLoaderRequest req, Throwable error){
doNotify(context, pn, accountID, notification, null);
}
}, true);
}
}
private void doNotify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification, Drawable avatar){
NotificationManager nm=context.getSystemService(NotificationManager.class);
Account self=AccountSessionManager.getInstance().getAccount(accountID).self;
String accountName="@"+self.username+"@"+AccountSessionManager.getInstance().getAccount(accountID).domain;
Notification.Builder builder;
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
boolean hasGroup=false;
int version=AccountSessionManager.get(accountID).getRawLocalPreferences().getInt("notificationChannelsVersion", 1);
List<NotificationChannelGroup> channelGroups=nm.getNotificationChannelGroups();
for(NotificationChannelGroup group:channelGroups){
if(group.getId().equals(accountID)){
@@ -116,7 +138,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
break;
}
}
if(!hasGroup){
if(!hasGroup || version!=2){
NotificationChannelGroup group=new NotificationChannelGroup(accountID, accountName);
nm.createNotificationChannelGroup(group);
List<NotificationChannel> channels=Arrays.stream(PushNotification.Type.values())
@@ -129,6 +151,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
})
.collect(Collectors.toList());
nm.createNotificationChannels(channels);
AccountSessionManager.get(accountID).getRawLocalPreferences().edit().putInt("notificationChannelsVersion", 2).apply();
}
builder=new Notification.Builder(context, accountID+"_"+pn.notificationType);
}else{
@@ -136,7 +159,6 @@ public class PushNotificationReceiver extends BroadcastReceiver{
.setPriority(Notification.PRIORITY_DEFAULT)
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
}
Drawable avatar=ImageCache.getInstance(context).get(new UrlImageLoaderRequest(pn.icon, V.dp(50), V.dp(50)));
Intent contentIntent=new Intent(context, MainActivity.class);
contentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
contentIntent.putExtra("fromNotification", true);
@@ -164,7 +186,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
builder.setSubText(accountName);
}
String notificationTag=accountID+"_"+(notification==null ? 0 : notification.id);
if(notification!=null && (notification.type==org.joinmastodon.android.model.Notification.Type.MENTION)){
if(notification!=null && (notification.type==NotificationType.MENTION)){
ArrayList<String> mentions=new ArrayList<>();
String ownID=AccountSessionManager.getInstance().getAccount(accountID).self.id;
if(!notification.status.account.id.equals(ownID))

View File

@@ -14,28 +14,35 @@ import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.api.requests.lists.GetLists;
import org.joinmastodon.android.api.requests.notifications.GetNotifications;
import org.joinmastodon.android.api.requests.notifications.GetNotificationsV1;
import org.joinmastodon.android.api.requests.notifications.GetNotificationsV2;
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.FollowList;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.NotificationGroup;
import org.joinmastodon.android.model.NotificationType;
import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.model.SearchResult;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.viewmodel.NotificationViewModel;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
@@ -43,7 +50,7 @@ import me.grishka.appkit.utils.WorkerThread;
public class CacheController{
private static final String TAG="CacheController";
private static final int DB_VERSION=3;
private static final int DB_VERSION=5;
public static final WorkerThread databaseThread=new WorkerThread("databaseThread");
public static final Handler uiHandler=new Handler(Looper.getMainLooper());
@@ -51,7 +58,7 @@ public class CacheController{
private DatabaseHelper db;
private final Runnable databaseCloseRunnable=this::closeDatabase;
private boolean loadingNotifications;
private final ArrayList<Callback<PaginatedResponse<List<Notification>>>> pendingNotificationsCallbacks=new ArrayList<>();
private final ArrayList<Callback<PaginatedResponse<List<NotificationViewModel>>>> pendingNotificationsCallbacks=new ArrayList<>();
private List<FollowList> lists;
private static final int POST_FLAG_GAP_AFTER=1;
@@ -135,75 +142,187 @@ public class CacheController{
});
}
public void getNotifications(String maxID, int count, boolean onlyMentions, boolean forceReload, Callback<PaginatedResponse<List<Notification>>> callback){
private List<NotificationViewModel> makeNotificationViewModels(List<NotificationGroup> notifications, Map<String, Account> accounts, Map<String, Status> statuses){
return notifications.stream()
.filter(ng->ng.type!=null)
.map(ng->{
NotificationViewModel nvm=new NotificationViewModel();
nvm.notification=ng;
nvm.accounts=ng.sampleAccountIds.stream().map(accounts::get).filter(Objects::nonNull).collect(Collectors.toList());
if(nvm.accounts.size()!=ng.sampleAccountIds.size())
return null;
if(ng.statusId!=null){
nvm.status=statuses.get(ng.statusId);
if(nvm.status==null)
return null;
}
return nvm;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
public void getNotifications(String maxID, int count, boolean onlyMentions, boolean forceReload, Callback<PaginatedResponse<List<NotificationViewModel>>> callback){
cancelDelayedClose();
databaseThread.postRunnable(()->{
try{
if(!onlyMentions && loadingNotifications){
synchronized(pendingNotificationsCallbacks){
pendingNotificationsCallbacks.add(callback);
}
return;
}
if(!forceReload){
SQLiteDatabase db=getOrOpenDatabase();
try(Cursor cursor=db.query(onlyMentions ? "notifications_mentions" : "notifications_all", new String[]{"json"}, maxID==null ? null : "`id`<?", maxID==null ? null : new String[]{maxID}, null, null, "`time` DESC", count+"")){
String suffix=onlyMentions ? "mentions" : "all";
String table="notifications_"+suffix;
String accountsTable="notifications_accounts_"+suffix;
String statusesTable="notifications_statuses_"+suffix;
try(Cursor cursor=db.query(table, new String[]{"json"}, maxID==null ? null : "`max_id`<?", maxID==null ? null : new String[]{maxID}, null, null, "`time` DESC", count+"")){
if(cursor.getCount()==count){
ArrayList<Notification> result=new ArrayList<>();
ArrayList<NotificationGroup> result=new ArrayList<>();
cursor.moveToFirst();
String newMaxID;
HashSet<String> needAccounts=new HashSet<>(), needStatuses=new HashSet<>();
do{
Notification ntf=MastodonAPIController.gson.fromJson(cursor.getString(0), Notification.class);
NotificationGroup ntf=MastodonAPIController.gson.fromJson(cursor.getString(0), NotificationGroup.class);
ntf.postprocess();
newMaxID=ntf.id;
newMaxID=ntf.pageMinId;
needAccounts.addAll(ntf.sampleAccountIds);
if(ntf.statusId!=null)
needStatuses.add(ntf.statusId);
result.add(ntf);
}while(cursor.moveToNext());
String _newMaxID=newMaxID;
AccountSessionManager.get(accountID).filterStatusContainingObjects(result, n->n.status, FilterContext.NOTIFICATIONS);
uiHandler.post(()->callback.onSuccess(new PaginatedResponse<>(result, _newMaxID)));
HashMap<String, Account> accounts=new HashMap<>();
HashMap<String, Status> statuses=new HashMap<>();
if(!needAccounts.isEmpty()){
try(Cursor cursor2=db.query(accountsTable, new String[]{"json"}, "`id` IN ("+String.join(", ", Collections.nCopies(needAccounts.size(), "?"))+")",
needAccounts.toArray(new String[0]), null, null, null)){
while(cursor2.moveToNext()){
Account acc=MastodonAPIController.gson.fromJson(cursor2.getString(0), Account.class);
acc.postprocess();
accounts.put(acc.id, acc);
}
}
}
if(!needStatuses.isEmpty()){
try(Cursor cursor2=db.query(statusesTable, new String[]{"json"}, "`id` IN ("+String.join(", ", Collections.nCopies(needStatuses.size(), "?"))+")",
needStatuses.toArray(new String[0]), null, null, null)){
while(cursor2.moveToNext()){
Status s=MastodonAPIController.gson.fromJson(cursor2.getString(0), Status.class);
s.postprocess();
statuses.put(s.id, s);
}
}
}
uiHandler.post(()->callback.onSuccess(new PaginatedResponse<>(makeNotificationViewModels(result, accounts, statuses), _newMaxID)));
return;
}
}catch(IOException x){
Log.w(TAG, "getNotifications: corrupted notification object in database", x);
}
}
if(!onlyMentions && loadingNotifications){
synchronized(pendingNotificationsCallbacks){
pendingNotificationsCallbacks.add(callback);
}
return;
}
if(!onlyMentions)
loadingNotifications=true;
new GetNotifications(maxID, count, onlyMentions ? EnumSet.of(Notification.Type.MENTION): EnumSet.allOf(Notification.Type.class))
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<Notification> result){
ArrayList<Notification> filtered=new ArrayList<>(result);
AccountSessionManager.get(accountID).filterStatusContainingObjects(filtered, n->n.status, FilterContext.NOTIFICATIONS);
PaginatedResponse<List<Notification>> res=new PaginatedResponse<>(filtered, result.isEmpty() ? null : result.get(result.size()-1).id);
callback.onSuccess(res);
putNotifications(result, onlyMentions, maxID==null);
if(!onlyMentions){
loadingNotifications=false;
synchronized(pendingNotificationsCallbacks){
for(Callback<PaginatedResponse<List<Notification>>> cb:pendingNotificationsCallbacks){
cb.onSuccess(res);
if(AccountSessionManager.get(accountID).getInstanceInfo().getApiVersion()>=2){
new GetNotificationsV2(maxID, count, onlyMentions ? EnumSet.of(NotificationType.MENTION): EnumSet.allOf(NotificationType.class), NotificationType.getGroupableTypes())
.setCallback(new Callback<>(){
@Override
public void onSuccess(GetNotificationsV2.GroupedNotificationsResults result){
Map<String, Account> accounts=result.accounts.stream().collect(Collectors.toMap(a->a.id, Function.identity(), (a1, a2)->a2));
Map<String, Status> statuses=result.statuses.stream().collect(Collectors.toMap(s->s.id, Function.identity(), (s1, s2)->s2));
List<NotificationViewModel> notifications=makeNotificationViewModels(result.notificationGroups, accounts, statuses);
databaseThread.postRunnable(()->putNotifications(result.notificationGroups, result.accounts, result.statuses, onlyMentions, maxID==null), 0);
PaginatedResponse<List<NotificationViewModel>> res=new PaginatedResponse<>(notifications,
result.notificationGroups.isEmpty() ? null : result.notificationGroups.get(result.notificationGroups.size()-1).pageMinId);
callback.onSuccess(res);
if(!onlyMentions){
loadingNotifications=false;
synchronized(pendingNotificationsCallbacks){
for(Callback<PaginatedResponse<List<NotificationViewModel>>> cb:pendingNotificationsCallbacks){
cb.onSuccess(res);
}
pendingNotificationsCallbacks.clear();
}
pendingNotificationsCallbacks.clear();
}
}
}
@Override
public void onError(ErrorResponse error){
callback.onError(error);
if(!onlyMentions){
loadingNotifications=false;
synchronized(pendingNotificationsCallbacks){
for(Callback<PaginatedResponse<List<Notification>>> cb:pendingNotificationsCallbacks){
cb.onError(error);
@Override
public void onError(ErrorResponse error){
callback.onError(error);
if(!onlyMentions){
loadingNotifications=false;
synchronized(pendingNotificationsCallbacks){
for(Callback<PaginatedResponse<List<NotificationViewModel>>> cb:pendingNotificationsCallbacks){
cb.onError(error);
}
pendingNotificationsCallbacks.clear();
}
pendingNotificationsCallbacks.clear();
}
}
}
})
.exec(accountID);
})
.exec(accountID);
}else{
new GetNotificationsV1(maxID, count, onlyMentions ? EnumSet.of(NotificationType.MENTION): EnumSet.allOf(NotificationType.class))
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<Notification> result){
ArrayList<Notification> filtered=new ArrayList<>(result);
AccountSessionManager.get(accountID).filterStatusContainingObjects(filtered, n->n.status, FilterContext.NOTIFICATIONS);
List<Status> statuses=filtered.stream().map(n->n.status).filter(Objects::nonNull).collect(Collectors.toList());
List<Account> accounts=filtered.stream().map(n->n.account).collect(Collectors.toList());
List<NotificationViewModel> converted=filtered.stream()
.map(n->{
NotificationGroup group=new NotificationGroup();
group.groupKey="converted-"+n.id;
group.notificationsCount=1;
group.type=n.type;
group.mostRecentNotificationId=group.pageMaxId=group.pageMinId=n.id;
group.latestPageNotificationAt=n.createdAt;
group.sampleAccountIds=List.of(n.account.id);
group.event=n.event;
group.moderationWarning=n.moderationWarning;
if(n.status!=null)
group.statusId=n.status.id;
NotificationViewModel nvm=new NotificationViewModel();
nvm.notification=group;
nvm.status=n.status;
nvm.accounts=List.of(n.account);
return nvm;
})
.collect(Collectors.toList());
PaginatedResponse<List<NotificationViewModel>> res=new PaginatedResponse<>(converted, result.isEmpty() ? null : result.get(result.size()-1).id);
callback.onSuccess(res);
if(!onlyMentions){
loadingNotifications=false;
synchronized(pendingNotificationsCallbacks){
for(Callback<PaginatedResponse<List<NotificationViewModel>>> cb:pendingNotificationsCallbacks){
cb.onSuccess(res);
}
pendingNotificationsCallbacks.clear();
}
}
databaseThread.postRunnable(()->putNotifications(converted.stream().map(nvm->nvm.notification).collect(Collectors.toList()), accounts, statuses, onlyMentions, maxID==null), 0);
}
@Override
public void onError(ErrorResponse error){
callback.onError(error);
if(!onlyMentions){
loadingNotifications=false;
synchronized(pendingNotificationsCallbacks){
for(Callback<PaginatedResponse<List<NotificationViewModel>>> cb:pendingNotificationsCallbacks){
cb.onError(error);
}
pendingNotificationsCallbacks.clear();
}
}
}
})
.exec(accountID);
}
}catch(SQLiteException x){
Log.w(TAG, x);
uiHandler.post(()->callback.onError(new MastodonErrorResponse(x.getLocalizedMessage(), 500, x)));
@@ -213,22 +332,40 @@ public class CacheController{
}, 0);
}
private void putNotifications(List<Notification> notifications, boolean onlyMentions, boolean clear){
private void putNotifications(List<NotificationGroup> notifications, List<Account> accounts, List<Status> statuses, boolean onlyMentions, boolean clear){
runOnDbThread((db)->{
String table=onlyMentions ? "notifications_mentions" : "notifications_all";
if(clear)
String suffix=onlyMentions ? "mentions" : "all";
String table="notifications_"+suffix;
String accountsTable="notifications_accounts_"+suffix;
String statusesTable="notifications_statuses_"+suffix;
if(clear){
db.delete(table, null, null);
db.delete(accountsTable, null, null);
db.delete(statusesTable, null, null);
}
ContentValues values=new ContentValues(4);
for(Notification n:notifications){
for(NotificationGroup n:notifications){
if(n.type==null){
continue;
}
values.put("id", n.id);
values.put("id", n.groupKey);
values.put("json", MastodonAPIController.gson.toJson(n));
values.put("type", n.type.ordinal());
values.put("time", n.createdAt.getEpochSecond());
values.put("time", n.latestPageNotificationAt.getEpochSecond());
values.put("max_id", n.pageMaxId);
db.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
values.clear();
for(Account acc:accounts){
values.put("id", acc.id);
values.put("json", MastodonAPIController.gson.toJson(acc));
db.insertWithOnConflict(accountsTable, null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
for(Status s:statuses){
values.put("id", s.id);
values.put("json", MastodonAPIController.gson.toJson(s));
db.insertWithOnConflict(statusesTable, null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
});
}
@@ -320,7 +457,7 @@ public class CacheController{
lists=result;
if(callback!=null)
callback.onSuccess(result);
writeListsToFile();
writeLists();
}
@Override
@@ -332,26 +469,22 @@ public class CacheController{
.exec(accountID);
}
private List<FollowList> loadListsFromFile(){
File file=getListsFile();
if(!file.exists())
return null;
try(InputStreamReader in=new InputStreamReader(new FileInputStream(file))){
return MastodonAPIController.gson.fromJson(in, new TypeToken<List<FollowList>>(){}.getType());
}catch(Exception x){
Log.w(TAG, "failed to read lists from cache file", x);
return null;
private List<FollowList> loadLists(){
SQLiteDatabase db=getOrOpenDatabase();
try(Cursor cursor=db.query("misc", new String[]{"value"}, "`key`=?", new String[]{"lists"}, null, null, null)){
if(!cursor.moveToFirst())
return null;
return MastodonAPIController.gson.fromJson(cursor.getString(0), new TypeToken<List<FollowList>>(){}.getType());
}
}
private void writeListsToFile(){
databaseThread.postRunnable(()->{
try(OutputStreamWriter out=new OutputStreamWriter(new FileOutputStream(getListsFile()))){
MastodonAPIController.gson.toJson(lists, out);
}catch(IOException x){
Log.w(TAG, "failed to write lists to cache file", x);
}
}, 0);
private void writeLists(){
runOnDbThread(db->{
ContentValues values=new ContentValues();
values.put("key", "lists");
values.put("value", MastodonAPIController.gson.toJson(lists));
db.insertWithOnConflict("misc", null, values, SQLiteDatabase.CONFLICT_REPLACE);
});
}
public void getLists(Callback<List<FollowList>> callback){
@@ -361,7 +494,7 @@ public class CacheController{
return;
}
databaseThread.postRunnable(()->{
List<FollowList> lists=loadListsFromFile();
List<FollowList> lists=loadLists();
if(lists!=null){
this.lists=lists;
if(callback!=null)
@@ -372,23 +505,19 @@ public class CacheController{
}, 0);
}
public File getListsFile(){
return new File(MastodonApp.context.getFilesDir(), "lists_"+accountID+".json");
}
public void addList(FollowList list){
if(lists==null)
return;
lists.add(list);
lists.sort(Comparator.comparing(l->l.title));
writeListsToFile();
writeLists();
}
public void deleteList(String id){
if(lists==null)
return;
lists.removeIf(l->l.id.equals(id));
writeListsToFile();
writeLists();
}
public void updateList(FollowList list){
@@ -398,7 +527,7 @@ public class CacheController{
if(lists.get(i).id.equals(list.id)){
lists.set(i, list);
lists.sort(Comparator.comparing(l->l.title));
writeListsToFile();
writeLists();
break;
}
}
@@ -419,23 +548,10 @@ public class CacheController{
`flags` INTEGER NOT NULL DEFAULT 0,
`time` INTEGER NOT NULL
)""");
db.execSQL("""
CREATE TABLE `notifications_all` (
`id` VARCHAR(25) NOT NULL PRIMARY KEY,
`json` TEXT NOT NULL,
`flags` INTEGER NOT NULL DEFAULT 0,
`type` INTEGER NOT NULL,
`time` INTEGER NOT NULL
)""");
db.execSQL("""
CREATE TABLE `notifications_mentions` (
`id` VARCHAR(25) NOT NULL PRIMARY KEY,
`json` TEXT NOT NULL,
`flags` INTEGER NOT NULL DEFAULT 0,
`type` INTEGER NOT NULL,
`time` INTEGER NOT NULL
)""");
createNotificationsTables(db, "all");
createNotificationsTables(db, "mentions");
createRecentSearchesTable(db);
createMiscTable(db);
}
@Override
@@ -446,6 +562,15 @@ public class CacheController{
if(oldVersion<3){
addTimeColumns(db);
}
if(oldVersion<4){
createMiscTable(db);
}
if(oldVersion<5){
db.execSQL("DROP TABLE `notifications_all`");
db.execSQL("DROP TABLE `notifications_mentions`");
createNotificationsTables(db, "all");
createNotificationsTables(db, "mentions");
}
}
private void createRecentSearchesTable(SQLiteDatabase db){
@@ -465,5 +590,36 @@ public class CacheController{
db.execSQL("ALTER TABLE `notifications_all` ADD `time` INTEGER NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE `notifications_mentions` ADD `time` INTEGER NOT NULL DEFAULT 0");
}
private void createMiscTable(SQLiteDatabase db){
db.execSQL("""
CREATE TABLE `misc` (
`key` TEXT NOT NULL PRIMARY KEY,
`value` TEXT
)""");
}
private void createNotificationsTables(SQLiteDatabase db, String suffix){
db.execSQL("CREATE TABLE `notifications_"+suffix+"` ("+
"""
`id` VARCHAR(100) NOT NULL PRIMARY KEY,
`json` TEXT NOT NULL,
`flags` INTEGER NOT NULL DEFAULT 0,
`type` INTEGER NOT NULL,
`time` INTEGER NOT NULL,
`max_id` VARCHAR(25) NOT NULL
)""");
db.execSQL("CREATE INDEX `notifications_"+suffix+"_max_id` ON `notifications_"+suffix+"`(`max_id`)");
db.execSQL("CREATE TABLE `notifications_accounts_"+suffix+"` ("+
"""
`id` VARCHAR(25) NOT NULL PRIMARY KEY,
`json` TEXT NOT NULL
)""");
db.execSQL("CREATE TABLE `notifications_statuses_"+suffix+"` ("+
"""
`id` VARCHAR(25) NOT NULL PRIMARY KEY,
`json` TEXT NOT NULL
)""");
}
}
}

View File

@@ -20,7 +20,7 @@ public class JsonObjectRequestBody extends RequestBody{
@Override
public MediaType contentType(){
return MediaType.get("application/json;charset=utf-8");
return MediaType.get("application/json");
}
@Override

View File

@@ -45,7 +45,6 @@ import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyAgreement;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
@@ -82,6 +81,7 @@ public class PushSubscriptionManager{
private static final String EXTRA_SENDER = "sender";
private static final String EXTRA_SCOPE = "scope";
private static final String KID_VALUE="|ID|1|"; // request ID?
private static final long TOKEN_REFRESH_INTERVAL=30*24*60*60*1000L;
private static String deviceToken;
private String accountID;
@@ -93,14 +93,19 @@ public class PushSubscriptionManager{
this.accountID=accountID;
}
public static void resetLocalPreferences(){
getPrefs().edit().clear().apply();
}
public static void tryRegisterFCM(){
deviceToken=getPrefs().getString("deviceToken", null);
int tokenVersion=getPrefs().getInt("version", 0);
if(!TextUtils.isEmpty(deviceToken) && tokenVersion==BuildConfig.VERSION_CODE){
long tokenLastRefreshed=getPrefs().getLong("lastRefresh", 0);
if(!TextUtils.isEmpty(deviceToken) && tokenVersion==BuildConfig.VERSION_CODE && System.currentTimeMillis()-tokenLastRefreshed<TOKEN_REFRESH_INTERVAL){
registerAllAccountsForPush(false);
return;
}
Log.i(TAG, "tryRegisterFCM: no token found or app was updated. Trying to get push token...");
Log.i(TAG, "tryRegisterFCM: no token found, token due for refresh, or app was updated. Trying to get push token...");
Intent intent = new Intent("com.google.iid.TOKEN_REQUEST");
intent.setPackage(GSF_PACKAGE);
intent.putExtra(EXTRA_APPLICATION_PENDING_INTENT,
@@ -146,7 +151,7 @@ public class PushSubscriptionManager{
session.pushPublicKey=Base64.encodeToString(publicKey.getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
session.pushAuthKey=encodedAuthKey=Base64.encodeToString(authKey, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
session.pushAccountID=pushAccountID=Base64.encodeToString(randomAccountID, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
AccountSessionManager.getInstance().writeAccountsFile();
AccountSessionManager.getInstance().writeAccountPushSettings(accountID);
}catch(NoSuchAlgorithmException|InvalidAlgorithmParameterException e){
Log.e(TAG, "registerAccountForPush: error generating encryption key", e);
return;
@@ -165,7 +170,7 @@ public class PushSubscriptionManager{
if(session==null)
return;
session.pushSubscription=result;
AccountSessionManager.getInstance().writeAccountsFile();
AccountSessionManager.getInstance().writeAccountPushSettings(accountID);
Log.d(TAG, "Successfully registered "+accountID+" for push notifications");
});
}
@@ -191,7 +196,7 @@ public class PushSubscriptionManager{
result.policy=subscription.policy;
session.pushSubscription=result;
session.needUpdatePushSettings=false;
AccountSessionManager.getInstance().writeAccountsFile();
AccountSessionManager.getInstance().writeAccountPushSettings(accountID);
}
@Override
@@ -204,7 +209,7 @@ public class PushSubscriptionManager{
return;
session.needUpdatePushSettings=true;
session.pushSubscription=subscription;
AccountSessionManager.getInstance().writeAccountsFile();
AccountSessionManager.getInstance().writeAccountPushSettings(accountID);
}
}
})
@@ -380,7 +385,11 @@ public class PushSubscriptionManager{
deviceToken=intent.getStringExtra("registration_id");
if(deviceToken.startsWith(KID_VALUE))
deviceToken=deviceToken.substring(KID_VALUE.length()+1);
getPrefs().edit().putString("deviceToken", deviceToken).putInt("version", BuildConfig.VERSION_CODE).apply();
getPrefs().edit()
.putString("deviceToken", deviceToken)
.putInt("version", BuildConfig.VERSION_CODE)
.putLong("lastRefresh", System.currentTimeMillis())
.apply();
Log.i(TAG, "Successfully registered for FCM");
registerAllAccountsForPush(true);
}else{

View File

@@ -31,7 +31,7 @@ import okio.Source;
public class ResizedImageRequestBody extends CountingRequestBody{
private File tempFile;
private Uri uri;
private String contentType;
private MediaType contentType;
private int maxSize;
public ResizedImageRequestBody(Uri uri, int maxSize, ProgressListener progressListener) throws IOException{
@@ -42,15 +42,16 @@ public class ResizedImageRequestBody extends CountingRequestBody{
opts.inJustDecodeBounds=true;
if("file".equals(uri.getScheme())){
BitmapFactory.decodeFile(uri.getPath(), opts);
contentType=UiUtils.getFileMediaType(new File(uri.getPath())).type();
contentType=UiUtils.getFileMediaType(new File(uri.getPath()));
}else{
try(InputStream in=MastodonApp.context.getContentResolver().openInputStream(uri)){
BitmapFactory.decodeStream(in, null, opts);
}
contentType=MastodonApp.context.getContentResolver().getType(uri);
String mime=MastodonApp.context.getContentResolver().getType(uri);
contentType=TextUtils.isEmpty(mime) ? null : MediaType.get(mime);
}
if(TextUtils.isEmpty(contentType))
contentType="image/jpeg";
if(contentType==null)
contentType=MediaType.get("image/jpeg");
if(needResize(opts.outWidth, opts.outHeight) || needCrop(opts.outWidth, opts.outHeight)){
Bitmap bitmap;
if(Build.VERSION.SDK_INT>=28){
@@ -136,7 +137,7 @@ public class ResizedImageRequestBody extends CountingRequestBody{
bitmap.compress(Bitmap.CompressFormat.PNG, 0, out);
}else{
bitmap.compress(Bitmap.CompressFormat.JPEG, 97, out);
contentType="image/jpeg";
contentType=MediaType.get("image/jpeg");
}
}
length=tempFile.length();
@@ -163,7 +164,7 @@ public class ResizedImageRequestBody extends CountingRequestBody{
@Override
public MediaType contentType(){
return MediaType.get(contentType);
return contentType;
}
@Override

View File

@@ -0,0 +1,21 @@
package org.joinmastodon.android.api;
import me.grishka.appkit.api.APIRequest;
/**
* Wraps a different API request to allow a chain of requests to be canceled
*/
public class WrapperRequest<T> extends APIRequest<T>{
public APIRequest<?> wrappedRequest;
@Override
public void cancel(){
if(wrappedRequest!=null)
wrappedRequest.cancel();
}
@Override
public APIRequest<T> exec(){
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,18 @@
package org.joinmastodon.android.api.requests.accounts;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.FamiliarFollowers;
import java.util.Collection;
import java.util.List;
public class GetAccountFamiliarFollowers extends MastodonAPIRequest<List<FamiliarFollowers>>{
public GetAccountFamiliarFollowers(Collection<String> ids){
super(HttpMethod.GET, "/accounts/familiar_followers", new TypeToken<>(){});
for(String id:ids){
addQueryParameter("id[]", id);
}
}
}

View File

@@ -0,0 +1,15 @@
package org.joinmastodon.android.api.requests.accounts;
import org.joinmastodon.android.api.MastodonAPIRequest;
public class GetDomainBlockPreview extends MastodonAPIRequest<GetDomainBlockPreview.Response>{
public GetDomainBlockPreview(String domain){
super(HttpMethod.GET, "/domain_blocks/preview", Response.class);
addQueryParameter("domain", domain);
}
public static class Response{
public int followingCount;
public int followersCount;
}
}

View File

@@ -0,0 +1,19 @@
package org.joinmastodon.android.api.requests.accounts;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Relationship;
public class SetPrivateNote extends MastodonAPIRequest<Relationship>{
public SetPrivateNote(String id, String comment){
super(MastodonAPIRequest.HttpMethod.POST, "/accounts/"+id+"/note", Relationship.class);
Request req = new Request(comment);
setRequestBody(req);
}
private static class Request{
public String comment;
public Request(String comment){
this.comment=comment;
}
}
}

View File

@@ -0,0 +1,10 @@
package org.joinmastodon.android.api.requests.announcements;
import org.joinmastodon.android.api.MastodonAPIRequest;
public class AddAnnouncementReaction extends MastodonAPIRequest<Object> {
public AddAnnouncementReaction(String id, String emoji) {
super(HttpMethod.PUT, "/announcements/" + id + "/reactions/" + emoji, Object.class);
setRequestBody(new Object());
}
}

View File

@@ -0,0 +1,9 @@
package org.joinmastodon.android.api.requests.announcements;
import org.joinmastodon.android.api.MastodonAPIRequest;
public class DeleteAnnouncementReaction extends MastodonAPIRequest<Object> {
public DeleteAnnouncementReaction(String id, String emoji) {
super(HttpMethod.DELETE, "/announcements/" + id + "/reactions/" + emoji, Object.class);
}
}

View File

@@ -0,0 +1,10 @@
package org.joinmastodon.android.api.requests.announcements;
import org.joinmastodon.android.api.MastodonAPIRequest;
public class DismissAnnouncement extends MastodonAPIRequest<Object>{
public DismissAnnouncement(String id){
super(HttpMethod.POST, "/announcements/" + id + "/dismiss", Object.class);
setRequestBody(new Object());
}
}

View File

@@ -0,0 +1,15 @@
package org.joinmastodon.android.api.requests.announcements;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Announcement;
import java.util.List;
public class GetAnnouncements extends MastodonAPIRequest<List<Announcement>> {
public GetAnnouncements(boolean withDismissed) {
super(MastodonAPIRequest.HttpMethod.GET, "/announcements", new TypeToken<>(){});
addQueryParameter("with_dismissed", withDismissed ? "true" : "false");
}
}

View File

@@ -1,10 +0,0 @@
package org.joinmastodon.android.api.requests.instance;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Instance;
public class GetInstance extends MastodonAPIRequest<Instance>{
public GetInstance(){
super(HttpMethod.GET, "/instance", Instance.class);
}
}

View File

@@ -0,0 +1,10 @@
package org.joinmastodon.android.api.requests.instance;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.InstanceV1;
public class GetInstanceV1 extends MastodonAPIRequest<InstanceV1>{
public GetInstanceV1(){
super(HttpMethod.GET, "/instance", InstanceV1.class);
}
}

View File

@@ -0,0 +1,15 @@
package org.joinmastodon.android.api.requests.instance;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.InstanceV2;
public class GetInstanceV2 extends MastodonAPIRequest<InstanceV2>{
public GetInstanceV2(){
super(HttpMethod.GET, "/instance", InstanceV2.class);
}
@Override
protected String getPathPrefix(){
return "/api/v2";
}
}

View File

@@ -0,0 +1,10 @@
package org.joinmastodon.android.api.requests.lists;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.FollowList;
public class GetList extends MastodonAPIRequest<FollowList> {
public GetList(String id) {
super(HttpMethod.GET, "/lists/" + id, FollowList.class);
}
}

View File

@@ -7,26 +7,27 @@ import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.ApiUtils;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.NotificationType;
import java.util.EnumSet;
import java.util.List;
public class GetNotifications extends MastodonAPIRequest<List<Notification>>{
public GetNotifications(String maxID, int limit, EnumSet<Notification.Type> includeTypes){
public class GetNotificationsV1 extends MastodonAPIRequest<List<Notification>>{
public GetNotificationsV1(String maxID, int limit, EnumSet<NotificationType> includeTypes){
this(maxID, limit, includeTypes, null);
}
public GetNotifications(String maxID, int limit, EnumSet<Notification.Type> includeTypes, String onlyAccountID){
public GetNotificationsV1(String maxID, int limit, EnumSet<NotificationType> includeTypes, String onlyAccountID){
super(HttpMethod.GET, "/notifications", new TypeToken<>(){});
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", ""+limit);
if(includeTypes!=null){
for(String type:ApiUtils.enumSetToStrings(includeTypes, Notification.Type.class)){
for(String type:ApiUtils.enumSetToStrings(includeTypes, NotificationType.class)){
addQueryParameter("types[]", type);
}
for(String type:ApiUtils.enumSetToStrings(EnumSet.complementOf(includeTypes), Notification.Type.class)){
for(String type:ApiUtils.enumSetToStrings(EnumSet.complementOf(includeTypes), NotificationType.class)){
addQueryParameter("exclude_types[]", type);
}
}

View File

@@ -0,0 +1,69 @@
package org.joinmastodon.android.api.requests.notifications;
import android.text.TextUtils;
import org.joinmastodon.android.api.AllFieldsAreRequired;
import org.joinmastodon.android.api.ApiUtils;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.BaseModel;
import org.joinmastodon.android.model.NotificationGroup;
import org.joinmastodon.android.model.NotificationType;
import org.joinmastodon.android.model.Status;
import java.util.EnumSet;
import java.util.List;
public class GetNotificationsV2 extends MastodonAPIRequest<GetNotificationsV2.GroupedNotificationsResults>{
public GetNotificationsV2(String maxID, int limit, EnumSet<NotificationType> includeTypes, EnumSet<NotificationType> groupedTypes){
this(maxID, limit, includeTypes, groupedTypes, null);
}
public GetNotificationsV2(String maxID, int limit, EnumSet<NotificationType> includeTypes, EnumSet<NotificationType> groupedTypes, String onlyAccountID){
super(HttpMethod.GET, "/notifications", GroupedNotificationsResults.class);
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", ""+limit);
if(includeTypes!=null){
for(String type:ApiUtils.enumSetToStrings(includeTypes, NotificationType.class)){
addQueryParameter("types[]", type);
}
for(String type:ApiUtils.enumSetToStrings(EnumSet.complementOf(includeTypes), NotificationType.class)){
addQueryParameter("exclude_types[]", type);
}
}
if(groupedTypes!=null){
for(String type:ApiUtils.enumSetToStrings(groupedTypes, NotificationType.class)){
addQueryParameter("grouped_types[]", type);
}
}
if(!TextUtils.isEmpty(onlyAccountID))
addQueryParameter("account_id", onlyAccountID);
removeUnsupportedItems=true;
}
@Override
protected String getPathPrefix(){
return "/api/v2";
}
@AllFieldsAreRequired
public static class GroupedNotificationsResults extends BaseModel{
public List<Account> accounts;
public List<Status> statuses;
public List<NotificationGroup> notificationGroups;
@Override
public void postprocess() throws ObjectValidationException{
super.postprocess();
for(Account acc:accounts)
acc.postprocess();
for(Status s:statuses)
s.postprocess();
for(NotificationGroup ng:notificationGroups)
ng.postprocess();
}
}
}

View File

@@ -0,0 +1,35 @@
package org.joinmastodon.android.api.requests.notifications;
import org.joinmastodon.android.api.ApiUtils;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.NotificationType;
import java.util.EnumSet;
public class GetUnreadNotificationsCount extends MastodonAPIRequest<GetUnreadNotificationsCount.Response>{
public GetUnreadNotificationsCount(EnumSet<NotificationType> includeTypes, EnumSet<NotificationType> groupedTypes){
super(HttpMethod.GET, "/notifications/unread_count", Response.class);
if(includeTypes!=null){
for(String type: ApiUtils.enumSetToStrings(includeTypes, NotificationType.class)){
addQueryParameter("types[]", type);
}
for(String type:ApiUtils.enumSetToStrings(EnumSet.complementOf(includeTypes), NotificationType.class)){
addQueryParameter("exclude_types[]", type);
}
}
if(groupedTypes!=null){
for(String type:ApiUtils.enumSetToStrings(groupedTypes, NotificationType.class)){
addQueryParameter("grouped_types[]", type);
}
}
}
@Override
protected String getPathPrefix(){
return "/api/v2";
}
public static class Response{
public int count;
}
}

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
public class AddStatusReaction extends MastodonAPIRequest<Status> {
public AddStatusReaction(String id, String emoji) {
super(HttpMethod.POST, "/statuses/" + id + "/react/" + emoji, Status.class);
setRequestBody(new Object());
}
}

View File

@@ -0,0 +1,10 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.AkkomaTranslation;
public class AkkomaTranslateStatus extends MastodonAPIRequest<AkkomaTranslation>{
public AkkomaTranslateStatus(String id, String lang){
super(HttpMethod.GET, "/statuses/"+id+"/translations/"+lang.toLowerCase(), AkkomaTranslation.class);
}
}

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
public class DeleteStatusReaction extends MastodonAPIRequest<Status> {
public DeleteStatusReaction(String id, String emoji) {
super(HttpMethod.POST, "/statuses/" + id + "/unreact/" + emoji, Status.class);
setRequestBody(new Object());
}
}

View File

@@ -0,0 +1,16 @@
package org.joinmastodon.android.api.requests.statuses;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
import org.joinmastodon.android.model.ScheduledStatus;
public class GetScheduledStatuses extends HeaderPaginationRequest<ScheduledStatus>{
public GetScheduledStatuses(String maxID, int limit){
super(HttpMethod.GET, "/scheduled_statuses", new TypeToken<>(){});
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", limit+"");
}
}

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
public class PleromaAddStatusReaction extends MastodonAPIRequest<Status> {
public PleromaAddStatusReaction(String id, String emoji) {
super(HttpMethod.PUT, "/pleroma/statuses/" + id + "/reactions/" + emoji, Status.class);
setRequestBody(new Object());
}
}

View File

@@ -0,0 +1,10 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
public class PleromaDeleteStatusReaction extends MastodonAPIRequest<Status> {
public PleromaDeleteStatusReaction(String id, String emoji) {
super(HttpMethod.DELETE, "/pleroma/statuses/" + id + "/reactions/" + emoji, Status.class);
}
}

View File

@@ -0,0 +1,14 @@
package org.joinmastodon.android.api.requests.statuses;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.EmojiReaction;
import java.util.List;
public class PleromaGetStatusReactions extends MastodonAPIRequest<List<EmojiReaction>> {
public PleromaGetStatusReactions(String id, String emoji) {
super(HttpMethod.GET, "/pleroma/statuses/" + id + "/reactions/" + (emoji != null ? emoji : ""), new TypeToken<>(){});
}
}

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