Full Code of Vavassor/Tusky for AI

develop 43ae0bb45563 cached
1670 files
8.3 MB
2.3M tokens
142 symbols
1 requests
Download .txt
Showing preview only (9,424K chars total). Download the full file or copy to clipboard to get everything.
Repository: Vavassor/Tusky
Branch: develop
Commit: 43ae0bb45563
Files: 1670
Total size: 8.3 MB

Directory structure:
gitextract_7rvtut99/

├── .editorconfig
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1.bug_report.yml
│   │   ├── 2.feature_request.yml
│   │   └── config.yml
│   ├── actions/
│   │   └── setup/
│   │       └── action.yml
│   ├── ci-gradle.properties
│   ├── renovate.json
│   └── workflows/
│       ├── check-and-build.yml
│       ├── deploy-release.yml
│       └── deploy-test.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── app/
│   ├── build.gradle
│   ├── getGitSha.gradle
│   ├── lint-baseline.xml
│   ├── lint.xml
│   ├── proguard-rules.pro
│   ├── schemas/
│   │   └── com.keylesspalace.tusky.db.AppDatabase/
│   │       ├── 10.json
│   │       ├── 11.json
│   │       ├── 12.json
│   │       ├── 13.json
│   │       ├── 14.json
│   │       ├── 15.json
│   │       ├── 16.json
│   │       ├── 17.json
│   │       ├── 18.json
│   │       ├── 19.json
│   │       ├── 20.json
│   │       ├── 21.json
│   │       ├── 22.json
│   │       ├── 23.json
│   │       ├── 24.json
│   │       ├── 25.json
│   │       ├── 26.json
│   │       ├── 27.json
│   │       ├── 28.json
│   │       ├── 29.json
│   │       ├── 30.json
│   │       ├── 31.json
│   │       ├── 32.json
│   │       ├── 33.json
│   │       ├── 34.json
│   │       ├── 35.json
│   │       ├── 36.json
│   │       ├── 37.json
│   │       ├── 38.json
│   │       ├── 39.json
│   │       ├── 40.json
│   │       ├── 41.json
│   │       ├── 42.json
│   │       ├── 43.json
│   │       ├── 44.json
│   │       ├── 45.json
│   │       ├── 46.json
│   │       ├── 47.json
│   │       ├── 48.json
│   │       ├── 49.json
│   │       ├── 50.json
│   │       ├── 51.json
│   │       ├── 52.json
│   │       ├── 53.json
│   │       ├── 54.json
│   │       ├── 56.json
│   │       ├── 58.json
│   │       ├── 60.json
│   │       ├── 62.json
│   │       ├── 64.json
│   │       ├── 66.json
│   │       ├── 68.json
│   │       └── 70.json
│   └── src/
│       ├── green/
│       │   └── res/
│       │       └── values/
│       │           └── flavor-colors.xml
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── keylesspalace/
│       │   │           └── tusky/
│       │   │               ├── AboutActivity.kt
│       │   │               ├── AccountsInListFragment.kt
│       │   │               ├── BaseActivity.kt
│       │   │               ├── BottomSheetActivity.kt
│       │   │               ├── EditProfileActivity.kt
│       │   │               ├── LicenseActivity.kt
│       │   │               ├── ListsActivity.kt
│       │   │               ├── MainActivity.kt
│       │   │               ├── MainViewModel.kt
│       │   │               ├── StatusListActivity.kt
│       │   │               ├── TabData.kt
│       │   │               ├── TabPreferenceActivity.kt
│       │   │               ├── TuskyApplication.kt
│       │   │               ├── ViewMediaActivity.kt
│       │   │               ├── adapter/
│       │   │               │   ├── AccountFieldEditAdapter.kt
│       │   │               │   ├── AccountSelectionAdapter.kt
│       │   │               │   ├── AccountViewHolder.kt
│       │   │               │   ├── EmojiAdapter.kt
│       │   │               │   ├── FilteredStatusViewHolder.kt
│       │   │               │   ├── FollowRequestViewHolder.kt
│       │   │               │   ├── LoadMoreViewHolder.kt
│       │   │               │   ├── LoadStateFooterAdapter.kt
│       │   │               │   ├── LocaleAdapter.kt
│       │   │               │   ├── PlaceholderViewHolder.kt
│       │   │               │   ├── PollAdapter.kt
│       │   │               │   ├── PreviewPollOptionsAdapter.kt
│       │   │               │   ├── StatusBaseViewHolder.java
│       │   │               │   ├── StatusDetailedViewHolder.java
│       │   │               │   ├── StatusViewHolder.java
│       │   │               │   └── TabAdapter.kt
│       │   │               ├── appstore/
│       │   │               │   ├── CacheUpdater.kt
│       │   │               │   ├── Events.kt
│       │   │               │   └── EventsHub.kt
│       │   │               ├── components/
│       │   │               │   ├── account/
│       │   │               │   │   ├── AccountActivity.kt
│       │   │               │   │   ├── AccountFieldAdapter.kt
│       │   │               │   │   ├── AccountPagerAdapter.kt
│       │   │               │   │   ├── AccountViewModel.kt
│       │   │               │   │   ├── list/
│       │   │               │   │   │   ├── ListSelectionFragment.kt
│       │   │               │   │   │   └── ListsForAccountViewModel.kt
│       │   │               │   │   └── media/
│       │   │               │   │       ├── AccountMediaFragment.kt
│       │   │               │   │       ├── AccountMediaGridAdapter.kt
│       │   │               │   │       ├── AccountMediaPagingSource.kt
│       │   │               │   │       ├── AccountMediaRemoteMediator.kt
│       │   │               │   │       ├── AccountMediaViewModel.kt
│       │   │               │   │       ├── GridSpacingItemDecoration.kt
│       │   │               │   │       └── SquareImageView.kt
│       │   │               │   ├── accountlist/
│       │   │               │   │   ├── AccountListActivity.kt
│       │   │               │   │   ├── AccountListFragment.kt
│       │   │               │   │   ├── AccountListPagingSource.kt
│       │   │               │   │   ├── AccountListRemoteMediator.kt
│       │   │               │   │   ├── AccountListViewModel.kt
│       │   │               │   │   ├── AccountViewData.kt
│       │   │               │   │   └── adapter/
│       │   │               │   │       ├── AccountAdapter.kt
│       │   │               │   │       ├── BlocksAdapter.kt
│       │   │               │   │       ├── FollowAdapter.kt
│       │   │               │   │       ├── FollowRequestsAdapter.kt
│       │   │               │   │       ├── FollowRequestsHeaderAdapter.kt
│       │   │               │   │       └── MutesAdapter.kt
│       │   │               │   ├── announcements/
│       │   │               │   │   ├── AnnouncementAdapter.kt
│       │   │               │   │   ├── AnnouncementsActivity.kt
│       │   │               │   │   └── AnnouncementsViewModel.kt
│       │   │               │   ├── compose/
│       │   │               │   │   ├── ComposeActivity.kt
│       │   │               │   │   ├── ComposeAutoCompleteAdapter.kt
│       │   │               │   │   ├── ComposeTokenizer.kt
│       │   │               │   │   ├── ComposeViewModel.kt
│       │   │               │   │   ├── ImageDownsizer.kt
│       │   │               │   │   ├── MediaPreviewAdapter.kt
│       │   │               │   │   ├── MediaUploader.kt
│       │   │               │   │   ├── dialog/
│       │   │               │   │   │   ├── AddPollDialog.kt
│       │   │               │   │   │   ├── AddPollOptionsAdapter.kt
│       │   │               │   │   │   ├── CaptionDialog.kt
│       │   │               │   │   │   └── FocusDialog.kt
│       │   │               │   │   └── view/
│       │   │               │   │       ├── ComposeOptionsView.kt
│       │   │               │   │       ├── ComposeScheduleView.kt
│       │   │               │   │       ├── EditTextTyped.kt
│       │   │               │   │       ├── FocusIndicatorView.kt
│       │   │               │   │       ├── PollPreviewView.kt
│       │   │               │   │       ├── ProgressImageView.kt
│       │   │               │   │       └── TootButton.kt
│       │   │               │   ├── conversation/
│       │   │               │   │   ├── ConversationEntity.kt
│       │   │               │   │   ├── ConversationPagingAdapter.kt
│       │   │               │   │   ├── ConversationViewData.kt
│       │   │               │   │   ├── ConversationViewHolder.java
│       │   │               │   │   ├── ConversationsFragment.kt
│       │   │               │   │   ├── ConversationsRemoteMediator.kt
│       │   │               │   │   └── ConversationsViewModel.kt
│       │   │               │   ├── domainblocks/
│       │   │               │   │   ├── DomainBlocksActivity.kt
│       │   │               │   │   ├── DomainBlocksAdapter.kt
│       │   │               │   │   ├── DomainBlocksFragment.kt
│       │   │               │   │   ├── DomainBlocksPagingSource.kt
│       │   │               │   │   ├── DomainBlocksRemoteMediator.kt
│       │   │               │   │   ├── DomainBlocksRepository.kt
│       │   │               │   │   └── DomainBlocksViewModel.kt
│       │   │               │   ├── drafts/
│       │   │               │   │   ├── DraftHelper.kt
│       │   │               │   │   ├── DraftMediaAdapter.kt
│       │   │               │   │   ├── DraftsActivity.kt
│       │   │               │   │   ├── DraftsAdapter.kt
│       │   │               │   │   └── DraftsViewModel.kt
│       │   │               │   ├── filters/
│       │   │               │   │   ├── EditFilterActivity.kt
│       │   │               │   │   ├── EditFilterViewModel.kt
│       │   │               │   │   ├── FilterExpiration.kt
│       │   │               │   │   ├── FilterExtensions.kt
│       │   │               │   │   ├── FiltersActivity.kt
│       │   │               │   │   ├── FiltersAdapter.kt
│       │   │               │   │   ├── FiltersListener.kt
│       │   │               │   │   └── FiltersViewModel.kt
│       │   │               │   ├── followedtags/
│       │   │               │   │   ├── FollowedTagsActivity.kt
│       │   │               │   │   ├── FollowedTagsAdapter.kt
│       │   │               │   │   ├── FollowedTagsPagingSource.kt
│       │   │               │   │   ├── FollowedTagsRemoteMediator.kt
│       │   │               │   │   └── FollowedTagsViewModel.kt
│       │   │               │   ├── instanceinfo/
│       │   │               │   │   ├── InstanceInfo.kt
│       │   │               │   │   └── InstanceInfoRepository.kt
│       │   │               │   ├── login/
│       │   │               │   │   ├── LoginActivity.kt
│       │   │               │   │   ├── LoginWebViewActivity.kt
│       │   │               │   │   └── LoginWebViewViewModel.kt
│       │   │               │   ├── notifications/
│       │   │               │   │   ├── FollowViewHolder.kt
│       │   │               │   │   ├── ModerationWarningViewHolder.kt
│       │   │               │   │   ├── NotificationPolicySummaryAdapter.kt
│       │   │               │   │   ├── NotificationTypeMappers.kt
│       │   │               │   │   ├── NotificationsFragment.kt
│       │   │               │   │   ├── NotificationsPagingAdapter.kt
│       │   │               │   │   ├── NotificationsRemoteMediator.kt
│       │   │               │   │   ├── NotificationsViewModel.kt
│       │   │               │   │   ├── ReportNotificationViewHolder.kt
│       │   │               │   │   ├── SeveredRelationshipNotificationViewHolder.kt
│       │   │               │   │   ├── StatusNotificationViewHolder.kt
│       │   │               │   │   ├── StatusViewHolder.kt
│       │   │               │   │   ├── UnknownNotificationViewHolder.kt
│       │   │               │   │   └── requests/
│       │   │               │   │       ├── NotificationRequestsActivity.kt
│       │   │               │   │       ├── NotificationRequestsAdapter.kt
│       │   │               │   │       ├── NotificationRequestsPagingSource.kt
│       │   │               │   │       ├── NotificationRequestsRemoteMediator.kt
│       │   │               │   │       ├── NotificationRequestsViewModel.kt
│       │   │               │   │       └── details/
│       │   │               │   │           ├── NotificationRequestDetailsActivity.kt
│       │   │               │   │           ├── NotificationRequestDetailsFragment.kt
│       │   │               │   │           ├── NotificationRequestDetailsPagingSource.kt
│       │   │               │   │           ├── NotificationRequestDetailsRemoteMediator.kt
│       │   │               │   │           └── NotificationRequestDetailsViewModel.kt
│       │   │               │   ├── preference/
│       │   │               │   │   ├── AccountPreferencesFragment.kt
│       │   │               │   │   ├── BasePreferencesFragment.kt
│       │   │               │   │   ├── NotificationPreferencesFragment.kt
│       │   │               │   │   ├── PreferencesActivity.kt
│       │   │               │   │   ├── PreferencesFragment.kt
│       │   │               │   │   ├── ProxyPreferencesFragment.kt
│       │   │               │   │   ├── TabFilterPreferencesFragment.kt
│       │   │               │   │   └── notificationpolicies/
│       │   │               │   │       ├── NotificationPoliciesActivity.kt
│       │   │               │   │       ├── NotificationPoliciesFragment.kt
│       │   │               │   │       ├── NotificationPoliciesViewModel.kt
│       │   │               │   │       └── NotificationPolicyPreference.kt
│       │   │               │   ├── report/
│       │   │               │   │   ├── ReportActivity.kt
│       │   │               │   │   ├── ReportViewModel.kt
│       │   │               │   │   ├── Screen.kt
│       │   │               │   │   ├── adapter/
│       │   │               │   │   │   ├── AdapterHandler.kt
│       │   │               │   │   │   ├── ReportPagerAdapter.kt
│       │   │               │   │   │   ├── StatusViewHolder.kt
│       │   │               │   │   │   ├── StatusesAdapter.kt
│       │   │               │   │   │   └── StatusesPagingSource.kt
│       │   │               │   │   ├── fragments/
│       │   │               │   │   │   ├── ReportDoneFragment.kt
│       │   │               │   │   │   ├── ReportNoteFragment.kt
│       │   │               │   │   │   └── ReportStatusesFragment.kt
│       │   │               │   │   └── model/
│       │   │               │   │       └── StatusViewState.kt
│       │   │               │   ├── scheduled/
│       │   │               │   │   ├── ScheduledStatusActivity.kt
│       │   │               │   │   ├── ScheduledStatusAdapter.kt
│       │   │               │   │   ├── ScheduledStatusPagingSource.kt
│       │   │               │   │   └── ScheduledStatusViewModel.kt
│       │   │               │   ├── search/
│       │   │               │   │   ├── SearchActivity.kt
│       │   │               │   │   ├── SearchType.kt
│       │   │               │   │   ├── SearchViewModel.kt
│       │   │               │   │   ├── adapter/
│       │   │               │   │   │   ├── SearchAccountsAdapter.kt
│       │   │               │   │   │   ├── SearchHashtagsAdapter.kt
│       │   │               │   │   │   ├── SearchPagerAdapter.kt
│       │   │               │   │   │   ├── SearchPagingSource.kt
│       │   │               │   │   │   ├── SearchPagingSourceFactory.kt
│       │   │               │   │   │   └── SearchStatusesAdapter.kt
│       │   │               │   │   └── fragments/
│       │   │               │   │       ├── SearchAccountsFragment.kt
│       │   │               │   │       ├── SearchFragment.kt
│       │   │               │   │       ├── SearchHashtagsFragment.kt
│       │   │               │   │       └── SearchStatusesFragment.kt
│       │   │               │   ├── systemnotifications/
│       │   │               │   │   ├── NotificationChannelData.kt
│       │   │               │   │   ├── NotificationFetcher.kt
│       │   │               │   │   └── NotificationService.kt
│       │   │               │   ├── timeline/
│       │   │               │   │   ├── TimelineFragment.kt
│       │   │               │   │   ├── TimelinePagingAdapter.kt
│       │   │               │   │   ├── TimelineTypeMappers.kt
│       │   │               │   │   ├── util/
│       │   │               │   │   │   └── TimelineUtils.kt
│       │   │               │   │   └── viewmodel/
│       │   │               │   │       ├── CachedTimelineRemoteMediator.kt
│       │   │               │   │       ├── CachedTimelineViewModel.kt
│       │   │               │   │       ├── NetworkTimelinePagingSource.kt
│       │   │               │   │       ├── NetworkTimelineRemoteMediator.kt
│       │   │               │   │       ├── NetworkTimelineViewModel.kt
│       │   │               │   │       └── TimelineViewModel.kt
│       │   │               │   ├── trending/
│       │   │               │   │   ├── TrendingActivity.kt
│       │   │               │   │   ├── TrendingDateViewHolder.kt
│       │   │               │   │   ├── TrendingTagViewHolder.kt
│       │   │               │   │   ├── TrendingTagsAdapter.kt
│       │   │               │   │   ├── TrendingTagsFragment.kt
│       │   │               │   │   └── viewmodel/
│       │   │               │   │       └── TrendingTagsViewModel.kt
│       │   │               │   └── viewthread/
│       │   │               │       ├── ConversationLineItemDecoration.kt
│       │   │               │       ├── ThreadAdapter.kt
│       │   │               │       ├── ViewThreadActivity.kt
│       │   │               │       ├── ViewThreadFragment.kt
│       │   │               │       ├── ViewThreadViewModel.kt
│       │   │               │       └── edits/
│       │   │               │           ├── ViewEditsAdapter.kt
│       │   │               │           ├── ViewEditsFragment.kt
│       │   │               │           └── ViewEditsViewModel.kt
│       │   │               ├── db/
│       │   │               │   ├── AccountManager.kt
│       │   │               │   ├── AppDatabase.java
│       │   │               │   ├── ConversationsDao.kt
│       │   │               │   ├── Converters.kt
│       │   │               │   ├── DatabaseCleaner.kt
│       │   │               │   ├── DraftsAlert.kt
│       │   │               │   ├── dao/
│       │   │               │   │   ├── AccountDao.kt
│       │   │               │   │   ├── DraftDao.kt
│       │   │               │   │   ├── InstanceDao.kt
│       │   │               │   │   ├── NotificationPolicyDao.kt
│       │   │               │   │   ├── NotificationsDao.kt
│       │   │               │   │   ├── TimelineAccountDao.kt
│       │   │               │   │   ├── TimelineDao.kt
│       │   │               │   │   └── TimelineStatusDao.kt
│       │   │               │   └── entity/
│       │   │               │       ├── AccountEntity.kt
│       │   │               │       ├── DraftEntity.kt
│       │   │               │       ├── HomeTimelineEntity.kt
│       │   │               │       ├── InstanceEntity.kt
│       │   │               │       ├── NotificationEntity.kt
│       │   │               │       ├── NotificationPolicyEntity.kt
│       │   │               │       ├── TimelineAccountEntity.kt
│       │   │               │       └── TimelineStatusEntity.kt
│       │   │               ├── di/
│       │   │               │   ├── CoroutineScopeModule.kt
│       │   │               │   ├── NetworkModule.kt
│       │   │               │   ├── NotificationManagerModule.kt
│       │   │               │   ├── PlayerModule.kt
│       │   │               │   ├── PreferencesEntryPoint.kt
│       │   │               │   └── StorageModule.kt
│       │   │               ├── entity/
│       │   │               │   ├── AccessToken.kt
│       │   │               │   ├── Account.kt
│       │   │               │   ├── AccountWarning.kt
│       │   │               │   ├── Announcement.kt
│       │   │               │   ├── AppCredentials.kt
│       │   │               │   ├── Attachment.kt
│       │   │               │   ├── Conversation.kt
│       │   │               │   ├── DeletedStatus.kt
│       │   │               │   ├── Emoji.kt
│       │   │               │   ├── Error.kt
│       │   │               │   ├── Filter.kt
│       │   │               │   ├── FilterKeyword.kt
│       │   │               │   ├── FilterResult.kt
│       │   │               │   ├── FilterV1.kt
│       │   │               │   ├── HashTag.kt
│       │   │               │   ├── Instance.kt
│       │   │               │   ├── InstanceV1.kt
│       │   │               │   ├── Marker.kt
│       │   │               │   ├── MastoList.kt
│       │   │               │   ├── MediaUploadResult.kt
│       │   │               │   ├── NewStatus.kt
│       │   │               │   ├── Notification.kt
│       │   │               │   ├── NotificationPolicy.kt
│       │   │               │   ├── NotificationRequest.kt
│       │   │               │   ├── NotificationSubscribeResult.kt
│       │   │               │   ├── Poll.kt
│       │   │               │   ├── PreviewCard.kt
│       │   │               │   ├── Relationship.kt
│       │   │               │   ├── RelationshipSeveranceEvent.kt
│       │   │               │   ├── Report.kt
│       │   │               │   ├── ScheduledStatus.kt
│       │   │               │   ├── SearchResult.kt
│       │   │               │   ├── Status.kt
│       │   │               │   ├── StatusContext.kt
│       │   │               │   ├── StatusEdit.kt
│       │   │               │   ├── StatusParams.kt
│       │   │               │   ├── StatusSource.kt
│       │   │               │   ├── TimelineAccount.kt
│       │   │               │   ├── Translation.kt
│       │   │               │   └── TrendingTagsResult.kt
│       │   │               ├── fragment/
│       │   │               │   ├── SFragment.kt
│       │   │               │   ├── ViewImageFragment.kt
│       │   │               │   ├── ViewMediaFragment.kt
│       │   │               │   └── ViewVideoFragment.kt
│       │   │               ├── interfaces/
│       │   │               │   ├── AccountActionListener.kt
│       │   │               │   ├── AccountSelectionListener.kt
│       │   │               │   ├── ActionButtonActivity.java
│       │   │               │   ├── HashtagActionListener.kt
│       │   │               │   ├── LinkListener.kt
│       │   │               │   ├── RefreshableFragment.kt
│       │   │               │   ├── ReselectableFragment.kt
│       │   │               │   └── StatusActionListener.kt
│       │   │               ├── json/
│       │   │               │   ├── Guarded.kt
│       │   │               │   ├── GuardedAdapter.kt
│       │   │               │   └── NotificationTypeAdapter.kt
│       │   │               ├── network/
│       │   │               │   ├── ApiFactory.kt
│       │   │               │   ├── FailingCall.kt
│       │   │               │   ├── FilterModel.kt
│       │   │               │   ├── MastodonApi.kt
│       │   │               │   ├── MediaUploadApi.kt
│       │   │               │   └── UriRequestBody.kt
│       │   │               ├── pager/
│       │   │               │   ├── ImagePagerAdapter.kt
│       │   │               │   ├── MainPagerAdapter.kt
│       │   │               │   └── SingleImagePagerAdapter.kt
│       │   │               ├── receiver/
│       │   │               │   ├── NotificationBlockStateBroadcastReceiver.kt
│       │   │               │   ├── SendStatusBroadcastReceiver.kt
│       │   │               │   └── UnifiedPushBroadcastReceiver.kt
│       │   │               ├── service/
│       │   │               │   ├── SendStatusService.kt
│       │   │               │   ├── ServiceClient.kt
│       │   │               │   └── TuskyTileService.kt
│       │   │               ├── settings/
│       │   │               │   ├── AccountPreferenceDataStore.kt
│       │   │               │   ├── DefaultReplyVisibility.kt
│       │   │               │   ├── ProxyConfiguration.kt
│       │   │               │   ├── SettingsConstants.kt
│       │   │               │   └── SettingsDSL.kt
│       │   │               ├── usecase/
│       │   │               │   ├── DeveloperToolsUseCase.kt
│       │   │               │   ├── LogoutUsecase.kt
│       │   │               │   ├── NotificationPolicyUsecase.kt
│       │   │               │   └── TimelineCases.kt
│       │   │               ├── util/
│       │   │               │   ├── AbsoluteTimeFormatter.kt
│       │   │               │   ├── ActivityExtensions.kt
│       │   │               │   ├── AlertDialogExtensions.kt
│       │   │               │   ├── AsciiFolding.kt
│       │   │               │   ├── AttachmentHelper.kt
│       │   │               │   ├── BindingHolder.kt
│       │   │               │   ├── BlurHashDecoder.kt
│       │   │               │   ├── BlurhashDrawable.kt
│       │   │               │   ├── BundleExtensions.kt
│       │   │               │   ├── CardViewMode.kt
│       │   │               │   ├── CompositeWithOpaqueBackground.kt
│       │   │               │   ├── CryptoUtil.kt
│       │   │               │   ├── CustomEmojiHelper.kt
│       │   │               │   ├── CustomFragmentStateAdapter.kt
│       │   │               │   ├── FocalPointUtil.kt
│       │   │               │   ├── GlideExtensions.kt
│       │   │               │   ├── GlideModule.kt
│       │   │               │   ├── HttpHeaderLink.kt
│       │   │               │   ├── IOUtils.kt
│       │   │               │   ├── IconUtils.kt
│       │   │               │   ├── ImageLoadingHelper.kt
│       │   │               │   ├── Lazy.kt
│       │   │               │   ├── LifecycleExtensions.kt
│       │   │               │   ├── LinkHelper.kt
│       │   │               │   ├── ListStatusAccessibilityDelegate.kt
│       │   │               │   ├── ListUtils.kt
│       │   │               │   ├── LocaleExtensions.kt
│       │   │               │   ├── LocaleManager.kt
│       │   │               │   ├── LocaleUtils.kt
│       │   │               │   ├── MediaUtils.kt
│       │   │               │   ├── NoUnderlineURLSpan.kt
│       │   │               │   ├── NumberUtils.kt
│       │   │               │   ├── PickMediaFiles.kt
│       │   │               │   ├── RelativeTimeUpdater.kt
│       │   │               │   ├── Resource.kt
│       │   │               │   ├── RickRoll.kt
│       │   │               │   ├── ShareShortcutHelper.kt
│       │   │               │   ├── SharedPreferencesExtensions.kt
│       │   │               │   ├── SmartLengthInputFilter.kt
│       │   │               │   ├── SpanUtils.kt
│       │   │               │   ├── StatusDisplayOptions.kt
│       │   │               │   ├── StatusParsingHelper.kt
│       │   │               │   ├── StatusViewHelper.kt
│       │   │               │   ├── StringUtils.kt
│       │   │               │   ├── ThemeUtils.kt
│       │   │               │   ├── ThrowableExtensions.kt
│       │   │               │   ├── TimestampUtils.kt
│       │   │               │   ├── TouchDelegateHelper.kt
│       │   │               │   ├── ViewBindingExtensions.kt
│       │   │               │   ├── ViewDataUtils.kt
│       │   │               │   ├── ViewExtensions.kt
│       │   │               │   └── twittertext/
│       │   │               │       ├── Regex.java
│       │   │               │       └── TldLists.java
│       │   │               ├── view/
│       │   │               │   ├── AdaptiveTabLayout.kt
│       │   │               │   ├── BackgroundMessageView.kt
│       │   │               │   ├── BezelImageView.kt
│       │   │               │   ├── ClickableSpanTextView.kt
│       │   │               │   ├── ConfirmationBottomSheet.kt
│       │   │               │   ├── EmojiPicker.kt
│       │   │               │   ├── GraphView.kt
│       │   │               │   ├── HashtagPickerDialog.kt
│       │   │               │   ├── LicenseCard.kt
│       │   │               │   ├── MediaPreviewImageView.kt
│       │   │               │   ├── MediaPreviewLayout.kt
│       │   │               │   ├── MuteAccountDialog.kt
│       │   │               │   ├── SliderPreference.kt
│       │   │               │   └── TuskySwipeRefreshLayout.kt
│       │   │               ├── viewdata/
│       │   │               │   ├── AttachmentViewData.kt
│       │   │               │   ├── NotificationViewData.kt
│       │   │               │   ├── PollViewData.kt
│       │   │               │   ├── StatusViewData.kt
│       │   │               │   └── TrendingViewData.kt
│       │   │               ├── viewmodel/
│       │   │               │   ├── AccountsInListViewModel.kt
│       │   │               │   ├── EditProfileViewModel.kt
│       │   │               │   └── ListsViewModel.kt
│       │   │               └── worker/
│       │   │                   ├── NotificationWorker.kt
│       │   │                   └── PruneCacheWorker.kt
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── activity_close_enter.xml
│       │       │   ├── activity_close_exit.xml
│       │       │   ├── activity_open_enter.xml
│       │       │   ├── activity_open_exit.xml
│       │       │   └── fast_out_extra_slow_in.xml
│       │       ├── color/
│       │       │   ├── account_tab_font_color.xml
│       │       │   ├── color_background_transparent_60.xml
│       │       │   ├── compound_button_color.xml
│       │       │   ├── selectable_chip_background.xml
│       │       │   └── text_input_layout_box_stroke_color.xml
│       │       ├── drawable/
│       │       │   ├── audio_file_preview.xml
│       │       │   ├── avatar_border.xml
│       │       │   ├── avatar_default.xml
│       │       │   ├── background_dialog_activity.xml
│       │       │   ├── badge_background.xml
│       │       │   ├── bot_badge.xml
│       │       │   ├── card_image_placeholder.xml
│       │       │   ├── conversation_thread_line.xml
│       │       │   ├── description_bg_expanded.xml
│       │       │   ├── dialog_background.xml
│       │       │   ├── elephant_friend.xml
│       │       │   ├── elephant_friend_empty.xml
│       │       │   ├── errorphant_error.xml
│       │       │   ├── errorphant_offline.xml
│       │       │   ├── ic_add_24dp.xml
│       │       │   ├── ic_add_a_photo_32dp_filled.xml
│       │       │   ├── ic_arrow_back_24dp.xml
│       │       │   ├── ic_arrow_drop_down_24dp.xml
│       │       │   ├── ic_arrow_drop_up_24dp.xml
│       │       │   ├── ic_attach_file_24dp.xml
│       │       │   ├── ic_block_24dp.xml
│       │       │   ├── ic_bookmark_24dp.xml
│       │       │   ├── ic_bookmark_24dp_filled.xml
│       │       │   ├── ic_bot_24dp.xml
│       │       │   ├── ic_bottom_navigation_24dp.xml
│       │       │   ├── ic_bottom_navigation_24dp_mirrored.xml
│       │       │   ├── ic_campaign_24dp.xml
│       │       │   ├── ic_cancel_24dp_filled.xml
│       │       │   ├── ic_check_24dp.xml
│       │       │   ├── ic_check_box_outline_blank_18dp.xml
│       │       │   ├── ic_check_circle_24dp.xml
│       │       │   ├── ic_chevron_right_24dp.xml
│       │       │   ├── ic_close_24dp.xml
│       │       │   ├── ic_comments_disabled_24dp.xml
│       │       │   ├── ic_content_copy_24dp.xml
│       │       │   ├── ic_developer_mode_24dp.xml
│       │       │   ├── ic_done_outline_24dp.xml
│       │       │   ├── ic_download_24dp.xml
│       │       │   ├── ic_drag_indicator_24dp.xml
│       │       │   ├── ic_edit_24dp_filled.xml
│       │       │   ├── ic_edit_document_24dp.xml
│       │       │   ├── ic_email_alternate_18dp.xml
│       │       │   ├── ic_email_alternate_24dp.xml
│       │       │   ├── ic_error_24dp.xml
│       │       │   ├── ic_feedback_24dp_filled.xml
│       │       │   ├── ic_filter_alt_24dp.xml
│       │       │   ├── ic_flag_24dp.xml
│       │       │   ├── ic_format_size_24dp.xml
│       │       │   ├── ic_gavel_24dp.xml
│       │       │   ├── ic_gif_box_24dp.xml
│       │       │   ├── ic_group_24dp.xml
│       │       │   ├── ic_group_24dp_filled.xml
│       │       │   ├── ic_heart_broken_24.xml
│       │       │   ├── ic_help_24dp.xml
│       │       │   ├── ic_home_24dp.xml
│       │       │   ├── ic_home_24dp_filled.xml
│       │       │   ├── ic_image_24dp.xml
│       │       │   ├── ic_info_24dp.xml
│       │       │   ├── ic_insert_chart_24dp.xml
│       │       │   ├── ic_insert_chart_24dp_filled.xml
│       │       │   ├── ic_list_alt_24dp.xml
│       │       │   ├── ic_list_alt_24dp_filled.xml
│       │       │   ├── ic_local_fire_department_24dp.xml
│       │       │   ├── ic_local_fire_department_24dp_filled.xml
│       │       │   ├── ic_lock_24dp.xml
│       │       │   ├── ic_lock_24dp_filled.xml
│       │       │   ├── ic_lock_open_24dp.xml
│       │       │   ├── ic_logout_24dp.xml
│       │       │   ├── ic_mail_24dp.xml
│       │       │   ├── ic_mail_24dp_filled.xml
│       │       │   ├── ic_manage_accounts_24dp.xml
│       │       │   ├── ic_mood_24dp.xml
│       │       │   ├── ic_more_horiz_24dp.xml
│       │       │   ├── ic_more_vert_24dp.xml
│       │       │   ├── ic_music_box_24dp.xml
│       │       │   ├── ic_notifications_24dp.xml
│       │       │   ├── ic_notifications_24dp_filled.xml
│       │       │   ├── ic_notifications_active_24dp.xml
│       │       │   ├── ic_open_in_new_24dp.xml
│       │       │   ├── ic_palette_24dp.xml
│       │       │   ├── ic_person_24dp.xml
│       │       │   ├── ic_person_add_24dp_mirrored.xml
│       │       │   ├── ic_person_add_24dp_mirrored_filled.xml
│       │       │   ├── ic_person_remove_24dp_mirrored.xml
│       │       │   ├── ic_photo_camera_24dp.xml
│       │       │   ├── ic_public_24dp.xml
│       │       │   ├── ic_radio_button_unchecked_18dp.xml
│       │       │   ├── ic_reblog_direct_24dp.xml
│       │       │   ├── ic_repeat_18dp.xml
│       │       │   ├── ic_repeat_24dp.xml
│       │       │   ├── ic_repeat_active_24dp.xml
│       │       │   ├── ic_reply_18dp.xml
│       │       │   ├── ic_reply_24dp.xml
│       │       │   ├── ic_reply_all_24dp.xml
│       │       │   ├── ic_schedule_24dp.xml
│       │       │   ├── ic_search_24dp.xml
│       │       │   ├── ic_send_24dp.xml
│       │       │   ├── ic_settings_24dp.xml
│       │       │   ├── ic_share_24dp.xml
│       │       │   ├── ic_slideshow_24dp.xml
│       │       │   ├── ic_sort_24dp.xml
│       │       │   ├── ic_spellcheck_24dp.xml
│       │       │   ├── ic_star_24dp.xml
│       │       │   ├── ic_star_24dp_filled.xml
│       │       │   ├── ic_tabs_24dp.xml
│       │       │   ├── ic_tag_24dp.xml
│       │       │   ├── ic_translate_24dp.xml
│       │       │   ├── ic_trip_24dp.xml
│       │       │   ├── ic_verified_18dp.xml
│       │       │   ├── ic_visibility_24dp.xml
│       │       │   ├── ic_visibility_off_24dp.xml
│       │       │   ├── ic_volume_off_24dp.xml
│       │       │   ├── ic_volume_up_24dp.xml
│       │       │   ├── ic_whatshot_24dp.xml
│       │       │   ├── ic_whatshot_24dp_filled.xml
│       │       │   ├── ic_zoom_in_24dp.xml
│       │       │   ├── ic_zoom_out_24dp.xml
│       │       │   ├── launcher_foreground.xml
│       │       │   ├── launcher_monochrome.xml
│       │       │   ├── materialdrawer_shape_large.xml
│       │       │   ├── materialdrawer_shape_small.xml
│       │       │   ├── media_preview_outline.xml
│       │       │   ├── media_warning_bg.xml
│       │       │   ├── play_indicator.xml
│       │       │   ├── poll_option_background.xml
│       │       │   ├── poll_option_shape.xml
│       │       │   ├── report_success_background.xml
│       │       │   ├── round_button.xml
│       │       │   ├── splashscreen.xml
│       │       │   ├── status_divider.xml
│       │       │   ├── tab_icon_bookmarks.xml
│       │       │   ├── tab_icon_direct.xml
│       │       │   ├── tab_icon_home.xml
│       │       │   ├── tab_icon_list.xml
│       │       │   ├── tab_icon_local.xml
│       │       │   ├── tab_icon_notifications.xml
│       │       │   ├── tab_icon_trending_posts.xml
│       │       │   ├── tab_icon_trending_tags.xml
│       │       │   ├── tab_indicator_bottom.xml
│       │       │   ├── tab_indicator_top.xml
│       │       │   ├── text_placeholder.xml
│       │       │   ├── toolbar_icon_arrow_back_with_background.xml
│       │       │   ├── toolbar_icon_more_with_background.xml
│       │       │   ├── tusky_notification_icon.xml
│       │       │   └── tusky_quicksettings_icon.xml
│       │       ├── layout/
│       │       │   ├── activity_about.xml
│       │       │   ├── activity_account.xml
│       │       │   ├── activity_account_list.xml
│       │       │   ├── activity_announcements.xml
│       │       │   ├── activity_compose.xml
│       │       │   ├── activity_drafts.xml
│       │       │   ├── activity_edit_filter.xml
│       │       │   ├── activity_edit_profile.xml
│       │       │   ├── activity_filters.xml
│       │       │   ├── activity_followed_tags.xml
│       │       │   ├── activity_license.xml
│       │       │   ├── activity_lists.xml
│       │       │   ├── activity_login.xml
│       │       │   ├── activity_login_webview.xml
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_notification_policy.xml
│       │       │   ├── activity_notification_request_details.xml
│       │       │   ├── activity_notification_requests.xml
│       │       │   ├── activity_preferences.xml
│       │       │   ├── activity_report.xml
│       │       │   ├── activity_scheduled_status.xml
│       │       │   ├── activity_search.xml
│       │       │   ├── activity_statuslist.xml
│       │       │   ├── activity_tab_preference.xml
│       │       │   ├── activity_trending.xml
│       │       │   ├── activity_view_media.xml
│       │       │   ├── activity_view_thread.xml
│       │       │   ├── bottomsheet_confirmation.xml
│       │       │   ├── card_license.xml
│       │       │   ├── dialog_add_poll.xml
│       │       │   ├── dialog_filter.xml
│       │       │   ├── dialog_focus.xml
│       │       │   ├── dialog_image_description.xml
│       │       │   ├── dialog_list.xml
│       │       │   ├── dialog_mute_account.xml
│       │       │   ├── dialog_pick_hashtag.xml
│       │       │   ├── exo_player_control_view.xml
│       │       │   ├── fragment_account_list.xml
│       │       │   ├── fragment_accounts_in_list.xml
│       │       │   ├── fragment_domain_blocks.xml
│       │       │   ├── fragment_lists_list.xml
│       │       │   ├── fragment_notification_request_details.xml
│       │       │   ├── fragment_report_done.xml
│       │       │   ├── fragment_report_note.xml
│       │       │   ├── fragment_report_statuses.xml
│       │       │   ├── fragment_search.xml
│       │       │   ├── fragment_timeline.xml
│       │       │   ├── fragment_timeline_notifications.xml
│       │       │   ├── fragment_trending_tags.xml
│       │       │   ├── fragment_view_edits.xml
│       │       │   ├── fragment_view_image.xml
│       │       │   ├── fragment_view_thread.xml
│       │       │   ├── fragment_view_video.xml
│       │       │   ├── item_account.xml
│       │       │   ├── item_account_field.xml
│       │       │   ├── item_account_media.xml
│       │       │   ├── item_add_poll_option.xml
│       │       │   ├── item_announcement.xml
│       │       │   ├── item_autocomplete_account.xml
│       │       │   ├── item_autocomplete_emoji.xml
│       │       │   ├── item_autocomplete_hashtag.xml
│       │       │   ├── item_blocked_domain.xml
│       │       │   ├── item_blocked_user.xml
│       │       │   ├── item_conversation.xml
│       │       │   ├── item_draft.xml
│       │       │   ├── item_edit_field.xml
│       │       │   ├── item_emoji_button.xml
│       │       │   ├── item_filtered_notifications_info.xml
│       │       │   ├── item_follow.xml
│       │       │   ├── item_follow_request.xml
│       │       │   ├── item_follow_requests_header.xml
│       │       │   ├── item_followed_hashtag.xml
│       │       │   ├── item_hashtag.xml
│       │       │   ├── item_image_preview_overlay.xml
│       │       │   ├── item_list.xml
│       │       │   ├── item_load_more.xml
│       │       │   ├── item_media_preview.xml
│       │       │   ├── item_moderation_warning_notification.xml
│       │       │   ├── item_muted_user.xml
│       │       │   ├── item_network_state.xml
│       │       │   ├── item_notification_request.xml
│       │       │   ├── item_notifications_load_state_footer_view.xml
│       │       │   ├── item_placeholder.xml
│       │       │   ├── item_poll.xml
│       │       │   ├── item_poll_preview_option.xml
│       │       │   ├── item_preview_card.xml
│       │       │   ├── item_reblog_option.xml
│       │       │   ├── item_removable.xml
│       │       │   ├── item_report_notification.xml
│       │       │   ├── item_report_status.xml
│       │       │   ├── item_scheduled_status.xml
│       │       │   ├── item_severed_relationship_notification.xml
│       │       │   ├── item_status.xml
│       │       │   ├── item_status_bottom_sheet.xml
│       │       │   ├── item_status_detailed.xml
│       │       │   ├── item_status_edit.xml
│       │       │   ├── item_status_filtered.xml
│       │       │   ├── item_status_notification.xml
│       │       │   ├── item_tab_preference.xml
│       │       │   ├── item_tab_preference_small.xml
│       │       │   ├── item_trending_cell.xml
│       │       │   ├── item_trending_date.xml
│       │       │   ├── item_unknown_notification.xml
│       │       │   ├── material_drawer_header.xml
│       │       │   ├── notifications_filter.xml
│       │       │   ├── pref_slider.xml
│       │       │   ├── preference_material_switch.xml
│       │       │   ├── preference_notification_policy.xml
│       │       │   ├── search_view.xml
│       │       │   ├── simple_list_item_1.xml
│       │       │   ├── toolbar_basic.xml
│       │       │   ├── view_background_message.xml
│       │       │   ├── view_compose_options.xml
│       │       │   ├── view_compose_schedule.xml
│       │       │   └── view_poll_preview.xml
│       │       ├── layout-land/
│       │       │   ├── fragment_report_done.xml
│       │       │   └── item_trending_cell.xml
│       │       ├── layout-sw640dp/
│       │       │   ├── fragment_timeline.xml
│       │       │   ├── fragment_timeline_notifications.xml
│       │       │   └── fragment_view_thread.xml
│       │       ├── menu/
│       │       │   ├── account_toolbar.xml
│       │       │   ├── activity_announcements.xml
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_notification_requests.xml
│       │       │   ├── activity_scheduled_status.xml
│       │       │   ├── conversation_more.xml
│       │       │   ├── edit_profile_toolbar.xml
│       │       │   ├── fragment_account_media.xml
│       │       │   ├── fragment_conversations.xml
│       │       │   ├── fragment_notifications.xml
│       │       │   ├── fragment_report_statuses.xml
│       │       │   ├── fragment_search.xml
│       │       │   ├── fragment_timeline.xml
│       │       │   ├── fragment_view_edits.xml
│       │       │   ├── fragment_view_thread.xml
│       │       │   ├── list_actions.xml
│       │       │   ├── search_toolbar.xml
│       │       │   ├── status_more.xml
│       │       │   ├── status_more_for_user.xml
│       │       │   ├── view_hashtag_toolbar.xml
│       │       │   └── view_media_toolbar.xml
│       │       ├── mipmap-anydpi-v26/
│       │       │   └── ic_launcher.xml
│       │       ├── raw/
│       │       │   ├── apache.txt
│       │       │   ├── isrg_root_x1.pem
│       │       │   └── isrg_root_x2.pem
│       │       ├── values/
│       │       │   ├── actions.xml
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── dimens.xml
│       │       │   ├── donottranslate.xml
│       │       │   ├── ids.xml
│       │       │   ├── string-arrays.xml
│       │       │   ├── strings.xml
│       │       │   ├── styles.xml
│       │       │   ├── theme_colors.xml
│       │       │   ├── toot_button.xml
│       │       │   └── values.xml
│       │       ├── values-ar/
│       │       │   └── strings.xml
│       │       ├── values-be/
│       │       │   └── strings.xml
│       │       ├── values-ber/
│       │       │   └── strings.xml
│       │       ├── values-bg/
│       │       │   └── strings.xml
│       │       ├── values-bn-rBD/
│       │       │   └── strings.xml
│       │       ├── values-bn-rIN/
│       │       │   └── strings.xml
│       │       ├── values-ca/
│       │       │   └── strings.xml
│       │       ├── values-ckb/
│       │       │   └── strings.xml
│       │       ├── values-cs/
│       │       │   └── strings.xml
│       │       ├── values-cy/
│       │       │   └── strings.xml
│       │       ├── values-de/
│       │       │   └── strings.xml
│       │       ├── values-el/
│       │       │   └── strings.xml
│       │       ├── values-en-rAU/
│       │       │   └── strings.xml
│       │       ├── values-en-rGB/
│       │       │   └── strings.xml
│       │       ├── values-eo/
│       │       │   └── strings.xml
│       │       ├── values-es/
│       │       │   └── strings.xml
│       │       ├── values-eu/
│       │       │   └── strings.xml
│       │       ├── values-fa/
│       │       │   └── strings.xml
│       │       ├── values-fi/
│       │       │   └── strings.xml
│       │       ├── values-fr/
│       │       │   └── strings.xml
│       │       ├── values-fr-rBE/
│       │       │   └── strings.xml
│       │       ├── values-fy/
│       │       │   └── strings.xml
│       │       ├── values-ga/
│       │       │   └── strings.xml
│       │       ├── values-gd/
│       │       │   └── strings.xml
│       │       ├── values-gl/
│       │       │   └── strings.xml
│       │       ├── values-hi/
│       │       │   └── strings.xml
│       │       ├── values-hu/
│       │       │   └── strings.xml
│       │       ├── values-in/
│       │       │   └── strings.xml
│       │       ├── values-is/
│       │       │   └── strings.xml
│       │       ├── values-it/
│       │       │   └── strings.xml
│       │       ├── values-iw/
│       │       │   └── strings.xml
│       │       ├── values-ja/
│       │       │   └── strings.xml
│       │       ├── values-kab/
│       │       │   └── strings.xml
│       │       ├── values-ko/
│       │       │   └── strings.xml
│       │       ├── values-large/
│       │       │   ├── dimens.xml
│       │       │   └── styles.xml
│       │       ├── values-large-land/
│       │       │   └── dimens.xml
│       │       ├── values-lb/
│       │       │   └── strings.xml
│       │       ├── values-lv/
│       │       │   └── strings.xml
│       │       ├── values-ml/
│       │       │   └── strings.xml
│       │       ├── values-nb-rNO/
│       │       │   └── strings.xml
│       │       ├── values-night/
│       │       │   └── theme_colors.xml
│       │       ├── values-nl/
│       │       │   └── strings.xml
│       │       ├── values-oc/
│       │       │   └── strings.xml
│       │       ├── values-or/
│       │       │   └── strings.xml
│       │       ├── values-pa/
│       │       │   └── strings.xml
│       │       ├── values-pl/
│       │       │   └── strings.xml
│       │       ├── values-pt-rBR/
│       │       │   └── strings.xml
│       │       ├── values-pt-rPT/
│       │       │   └── strings.xml
│       │       ├── values-ru/
│       │       │   └── strings.xml
│       │       ├── values-sa/
│       │       │   └── strings.xml
│       │       ├── values-si/
│       │       │   └── strings.xml
│       │       ├── values-sk/
│       │       │   └── strings.xml
│       │       ├── values-sl/
│       │       │   └── strings.xml
│       │       ├── values-small/
│       │       │   └── integer.xml
│       │       ├── values-sv/
│       │       │   └── strings.xml
│       │       ├── values-sw380dp/
│       │       │   └── toot_button.xml
│       │       ├── values-ta/
│       │       │   └── strings.xml
│       │       ├── values-te/
│       │       │   └── strings.xml
│       │       ├── values-th/
│       │       │   └── strings.xml
│       │       ├── values-tr/
│       │       │   └── strings.xml
│       │       ├── values-uk/
│       │       │   └── strings.xml
│       │       ├── values-v27/
│       │       │   └── styles.xml
│       │       ├── values-v35/
│       │       │   └── values.xml
│       │       ├── values-vi/
│       │       │   └── strings.xml
│       │       ├── values-w640dp/
│       │       │   ├── dimens.xml
│       │       │   └── integers.xml
│       │       ├── values-zh-rCN/
│       │       │   └── strings.xml
│       │       ├── values-zh-rHK/
│       │       │   └── strings.xml
│       │       ├── values-zh-rMO/
│       │       │   └── strings.xml
│       │       ├── values-zh-rSG/
│       │       │   └── strings.xml
│       │       ├── values-zh-rTW/
│       │       │   └── strings.xml
│       │       └── xml/
│       │           ├── file_paths.xml
│       │           ├── locales_config.xml
│       │           ├── network_security_config.xml
│       │           ├── searchable.xml
│       │           └── share_shortcuts.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── keylesspalace/
│                       └── tusky/
│                           ├── BottomSheetActivityTest.kt
│                           ├── FilterV1Test.kt
│                           ├── FocalPointUtilTest.kt
│                           ├── MainActivityTest.kt
│                           ├── SpanUtilsTest.kt
│                           ├── StatusComparisonTest.kt
│                           ├── StringUtilsTest.kt
│                           ├── TuskyApplication.kt
│                           ├── components/
│                           │   ├── compose/
│                           │   │   ├── ComposeActivityTest.kt
│                           │   │   ├── ComposeTokenizerTest.kt
│                           │   │   ├── ComposeViewModelTest.kt
│                           │   │   └── StatusLengthTest.kt
│                           │   ├── notifications/
│                           │   │   ├── NotificationFaker.kt
│                           │   │   └── NotificationsRemoteMediatorTest.kt
│                           │   ├── timeline/
│                           │   │   ├── CachedTimelineRemoteMediatorTest.kt
│                           │   │   ├── NetworkTimelinePagingSourceTest.kt
│                           │   │   ├── NetworkTimelineRemoteMediatorTest.kt
│                           │   │   └── TimelineFaker.kt
│                           │   └── viewthread/
│                           │       └── ViewThreadViewModelTest.kt
│                           ├── db/
│                           │   ├── MigrationsTest.kt
│                           │   └── dao/
│                           │       ├── DatabaseCleanerTest.kt
│                           │       ├── NotificationsDaoTest.kt
│                           │       └── TimelineDaoTest.kt
│                           ├── entity/
│                           │   └── ProxyConfigurationTest.kt
│                           ├── json/
│                           │   └── GuardedAdapterTest.kt
│                           ├── network/
│                           │   └── ApiFactoryTest.kt
│                           ├── usecase/
│                           │   └── TimelineCasesTest.kt
│                           └── util/
│                               ├── AbsoluteTimeFormatterTest.kt
│                               ├── HttpHeaderLinkTest.kt
│                               ├── LinkHelperTest.kt
│                               ├── LocaleUtilsTest.kt
│                               ├── NumberUtilsTest.kt
│                               ├── RickRollTest.kt
│                               ├── SmartLengthInputFilterTest.kt
│                               └── TimestampUtilsTest.kt
├── assets/
│   └── tusky_banner.xcf
├── build.gradle
├── doc/
│   ├── PaymentPolicy.md
│   └── Release.md
├── fastlane/
│   └── metadata/
│       └── android/
│           ├── ar/
│           │   ├── changelogs/
│           │   │   ├── 61.txt
│           │   │   ├── 68.txt
│           │   │   └── 70.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── be/
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── bg/
│           │   ├── changelogs/
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 74.txt
│           │   │   └── 77.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── bn-BD/
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── bn-IN/
│           │   ├── changelogs/
│           │   │   └── 67.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ca/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ckb/
│           │   ├── changelogs/
│           │   │   └── 77.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── cs/
│           │   ├── changelogs/
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── cy/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── de/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── el/
│           │   ├── changelogs/
│           │   │   └── 100.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── en-US/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── eo/
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── es/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── eu/
│           │   ├── changelogs/
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── fa/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── fi/
│           │   └── title.txt
│           ├── fr/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ga/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── gd/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── gl/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── hi/
│           │   ├── changelogs/
│           │   │   └── 68.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── hu/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── id/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── is/
│           │   ├── changelogs/
│           │   │   ├── 127.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   └── 89.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── it/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 74.txt
│           │   │   └── 77.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ja/
│           │   ├── changelogs/
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   └── 74.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── kab/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ko/
│           │   ├── changelogs/
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   └── 67.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── lv/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── nb-NO/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── nl/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   └── 94.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── pl/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── pt-BR/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── pt-PT/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 117.txt
│           │   │   ├── 131.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   └── 91.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ru/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── sa/
│           │   ├── changelogs/
│           │   │   ├── 72.txt
│           │   │   └── 74.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── si/
│           │   └── title.txt
│           ├── sk/
│           │   ├── changelogs/
│           │   │   ├── 67.txt
│           │   │   └── 68.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── sl/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   └── 104.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── sv/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ta/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── th/
│           │   ├── changelogs/
│           │   │   └── 72.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── tr/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── uk/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── vi/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── zh-Hans/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           └── zh-Hant/
│               ├── full_description.txt
│               ├── short_description.txt
│               └── title.txt
├── gradle/
│   ├── libs.versions.toml
│   ├── verification-metadata.xml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[*.{java,kt}]
ij_kotlin_imports_layout = *

# Disable wildcard imports
ij_kotlin_name_count_to_use_star_import = 999
ij_kotlin_name_count_to_use_star_import_for_members = 999
ij_java_class_count_to_use_import_on_demand = 999

ktlint_code_style = android_studio

# Disable trailing comma
ktlint_standard_trailing-comma-on-call-site = disabled
ktlint_standard_trailing-comma-on-declaration-site = disabled

max_line_length = off

[*.{yml,yaml}]
indent_size = 2


================================================
FILE: .gitattributes
================================================
* text=auto eol=lf

*.bat text eol=crlf
*.jar binary


================================================
FILE: .github/FUNDING.yml
================================================
open_collective: tusky


================================================
FILE: .github/ISSUE_TEMPLATE/1.bug_report.yml
================================================
name: Bug Report
description: If something isn't working as expected
labels: [bug]
body:
  - type: markdown
    attributes:
      value: |
        Make sure that you are submitting a new bug that was not previously reported or already fixed.

        Please use a concise and distinct title for the issue.

        If possible, attach screenshots, videos or links to posts to illustrate the problem.
  - type: textarea
    attributes:
      label: Detailed description
    validations:
      required: false
  - type: textarea
    attributes:
      label: Steps to reproduce the problem
      description: What were you trying to do?
      value: |
        1.
        2.
        3.
        ...
    validations:
      required: false
  - type: textarea
    attributes:
      label: Debug information
      description: |
        This info can be copied from the 'About' screen in Tusky 24+.
        If you are on a lower version or can't access the screen, please provide us with the Tusky Version, Android Version, Device and the Mastodon instance this problem occurred on.
      placeholder: |
        Tusky Test 22.0-b814c2c0
        Android 12
        Fairphone 4
        mastodon.social
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/2.feature_request.yml
================================================
name: Feature Request
description: I have a suggestion
labels: [enhancement]
body:
  - type: markdown
    attributes:
      value: Please use a concise and distinct title for the issue.
  - type: textarea
    attributes:
      label: Pitch
      description: Describe your idea for a feature. Make sure it has not already been suggested/implemented/turned down before.
    validations:
      required: true
  - type: textarea
    attributes:
      label: Motivation
      description: Why do you think this feature is needed? Who would benefit from it?
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true


================================================
FILE: .github/actions/setup/action.yml
================================================
name: 'Setup build environment'
description: 'Sets up an environment for building Tusky'
runs:
  using: "composite"
  steps:
    - uses: actions/setup-java@v4
      with:
        java-version: '21'
        distribution: 'temurin'

    - name: Copy CI gradle.properties
      shell: bash
      run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties

    - name: Gradle Build Action
      uses: gradle/actions/setup-gradle@v4
      with:
        cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/develop' }}


================================================
FILE: .github/ci-gradle.properties
================================================
#
# Copyright 2023 Tusky Contributors
#
# This file is a part of Tusky.
#
# This program is free software; you can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along with Tusky; if not,
# see <http://www.gnu.org/licenses>.
#

# CI build workers are ephemeral, so don't benefit from the Gradle daemon
org.gradle.daemon=false
org.gradle.parallel=true
org.gradle.workers.max=2

kotlin.incremental=false
kotlin.compiler.execution.strategy=in-process


================================================
FILE: .github/renovate.json
================================================
{
    "$schema": "https://docs.renovatebot.com/renovate-schema.json",
    "extends": [
        "config:recommended"
    ],
    "packageRules": [
        {
            "groupName": "Kotlin",
            "groupSlug": "kotlin",
            "matchPackageNames": [
                "com.google.devtools.ksp{/,}**",
                "/org.jetbrains.kotlin.*/"
            ]
        }
    ]
}


================================================
FILE: .github/workflows/check-and-build.yml
================================================
name: Check and build

on:
  pull_request:
  workflow_call:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup
        uses: ./.github/actions/setup

      - name: Licensee
        run: ./gradlew licensee

      - name: ktlint
        run: ./gradlew clean ktlintCheck

      - name: Regular lint
        run: ./gradlew app:lintGreenDebug

      - name: Test
        run: ./gradlew app:testGreenDebugUnitTest

      - name: Build
        run: ./gradlew app:buildGreenDebug


================================================
FILE: .github/workflows/deploy-release.yml
================================================
# When a tag is created, create a release build and upload it to Google Play

name: Deploy release to Google Play

on:
  push:
    tags:
      - '*'

jobs:
  check-and-build:
    uses: ./.github/workflows/check-and-build.yml
  deploy:
    runs-on: ubuntu-latest
    needs: check-and-build
    environment: Release
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup
        uses: ./.github/actions/setup

      - name: Build Blue aab
        run: ./gradlew app:bundleBlueRelease

      - uses: r0adkll/sign-android-release@f30bdd30588842ac76044ecdbd4b6d0e3e813478
        name: Sign Tusky Blue aab
        id: sign_aab
        with:
          releaseDirectory: app/build/outputs/bundle/blueRelease
          signingKeyBase64: ${{ secrets.KEYSTORE }}
          alias: ${{ secrets.KEY_ALIAS }}
          keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }}
          keyPassword: ${{ secrets.KEY_PASSWORD }}

      - name: Generate whatsnew
        id: generate-whatsnew
        run: |
          mkdir whatsnew
          cp $(find fastlane/metadata/android/en-US/changelogs | sort -n -k6 -t/ | tail -n 1) whatsnew/whatsnew-en-US

      - name: Upload AAB to Google Play
        id: upload-release-asset-aab
        uses: r0adkll/upload-google-play@v1.1.3
        with:
          serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
          packageName: com.keylesspalace.tusky
          releaseFiles: ${{steps.sign_aab.outputs.signedReleaseFile}}
          track: internal
          whatsNewDirectory: whatsnew
          status: completed
          mappingFile: app/build/outputs/mapping/blueRelease/mapping.txt


================================================
FILE: .github/workflows/deploy-test.yml
================================================
# Deploy Tusky Nightly on each push to develop

name: Deploy Tusky Nightly to Google Play

on:
  push:
    branches:
      - develop

concurrency:
  group: ${{ github.workflow }}
  cancel-in-progress: true

jobs:
  check-and-build:
    uses: ./.github/workflows/check-and-build.yml
  deploy:
    runs-on: ubuntu-latest
    needs: check-and-build
    environment: Test
    env:
      BUILD_NUMBER: ${{ github.run_number }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup
        uses: ./.github/actions/setup

      - name: Set versionCode
        run: |
          export VERSION_CODE=$(( ${BUILD_NUMBER} + 11000 ))
          sed -i'.original' -e "s/^\([[:space:]]*versionCode[[:space:]]*\)[0-9]*/\\1$VERSION_CODE/" app/build.gradle

      - name: Build Green aab
        run: ./gradlew app:bundleGreenRelease

      - uses: r0adkll/sign-android-release@f30bdd30588842ac76044ecdbd4b6d0e3e813478
        name: Sign Tusky Green aab
        id: sign_aab
        with:
          releaseDirectory: app/build/outputs/bundle/greenRelease
          signingKeyBase64: ${{ secrets.KEYSTORE }}
          alias: ${{ secrets.KEY_ALIAS }}
          keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }}
          keyPassword: ${{ secrets.KEY_PASSWORD }}

      - name: Generate whatsnew
        id: generate-whatsnew
        run: |
          mkdir whatsnew
          git log -3 --pretty=%B | head -c 500 > whatsnew/whatsnew-en-US

      - name: Upload AAB to Google Play
        id: upload-release-asset-aab
        uses: r0adkll/upload-google-play@v1.1.3
        with:
          serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
          packageName: com.keylesspalace.tusky.test
          releaseFiles: ${{steps.sign_aab.outputs.signedReleaseFile}}
          track: production
          whatsNewDirectory: whatsnew
          status: completed
          mappingFile: app/build/outputs/mapping/greenRelease/mapping.txt


================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea
.DS_Store
build
/captures
.externalNativeBuild
app/release
app-release.apk
.kotlin


================================================
FILE: CHANGELOG.md
================================================
# Tusky changelog

## Unreleased or Tusky Nightly

### New features and other improvements

### Significant bug fixes

## v29.0

### New features and other improvements

- New iconset https://github.com/tuskyapp/Tusky/pull/5012
- The layout of polls has been improved and a "show results" button was added https://github.com/tuskyapp/Tusky/pull/4980 https://github.com/tuskyapp/Tusky/pull/5047 https://github.com/tuskyapp/Tusky/pull/5095
- Support for the "blur" filter action (Mastodon 4.4 feature) https://github.com/tuskyapp/Tusky/pull/5038
- The quality of the image viewer has been improved https://github.com/tuskyapp/Tusky/pull/5068 https://github.com/tuskyapp/Tusky/pull/5067
- An additional dialog will now prevent accidentally dismissing the media caption dialog https://github.com/tuskyapp/Tusky/pull/4999
- Tusky will now send a `delete_media` parameter when deleting a post to help servers clean up their media faster (Mastodon 4.4 feature) https://github.com/tuskyapp/Tusky/pull/5082
- Boosts and favorites are now confirmed via a bottom sheet instead of a drop down https://github.com/tuskyapp/Tusky/pull/5084
- All account list views now have better error handling https://github.com/tuskyapp/Tusky/pull/5028
- Support for Android 16 https://github.com/tuskyapp/Tusky/pull/5071
- Several internal code improvements https://github.com/tuskyapp/Tusky/pull/5036 https://github.com/tuskyapp/Tusky/pull/5094 https://github.com/tuskyapp/Tusky/pull/5055 https://github.com/tuskyapp/Tusky/pull/5024
- Improved localizations

### Significant bug fixes

- caches are now correctly deleted when logging out https://github.com/tuskyapp/Tusky/pull/4997 https://github.com/tuskyapp/Tusky/pull/5004
- several layout fixes on Android 15+ https://github.com/tuskyapp/Tusky/pull/5053 https://github.com/tuskyapp/Tusky/pull/5041 https://github.com/tuskyapp/Tusky/pull/5003
- fixes a crash that occurs when Tusky is used on a device with two or more UnifiedPush providers https://github.com/tuskyapp/Tusky/pull/5015

## v28.0

### New features and other improvements

- Support for Android 15 and edge-to-edge mode https://github.com/tuskyapp/Tusky/pull/4897
- Improves the reliability of push notifications https://github.com/tuskyapp/Tusky/pull/4896 https://github.com/tuskyapp/Tusky/pull/4883
- Replies in timeline are now clearly marked as such by a text above them https://github.com/tuskyapp/Tusky/pull/4834
- Several improvements to how notifications are rendered in the notifications tab https://github.com/tuskyapp/Tusky/pull/4929
  - support for the new Mastodon 4.3 notification types `severed_relationships` and `moderation_warning`
  - The "unknown notification type" notification now shows the unknown type and a info dialog when you click it
  - The account note is now shown again for follow request and follow notifications
  - The icon for the "<user> just posted" notification is now a bell instead of a home
  - Adds a text above mention notifications that indicates if it is a (private) reply or (private) mention
  - Follow requests won't be filtered by default in the notification tab. This change will only affect new logins and not existing ones.
- Link Preview Cards got a new design and now support the fediverse:creator feature https://github.com/tuskyapp/Tusky/pull/4782
- The possible selections for mute durations are now 1 hour, 6 hours, 1 day, 7 days, 30 days and 180 days https://github.com/tuskyapp/Tusky/pull/4943
- The rendering of trending tags has been improved https://github.com/tuskyapp/Tusky/pull/4889 https://github.com/tuskyapp/Tusky/pull/4924
- The app will no longer make database queries on the main thread, which improves performance https://github.com/tuskyapp/Tusky/pull/4786
- Wellbeing mode will no longer hide the "follows you" badge on profiles https://github.com/tuskyapp/Tusky/pull/4940
- It is now possible to select boost visibility when the "Show confirmation before boosting" option is active https://github.com/tuskyapp/Tusky/pull/4944

### Significant bug fixes

- Fixes a bug where more than 4 profile fields could not be edited (on instances that allow more than 4) https://github.com/tuskyapp/Tusky/commit/1157be18cf3bbd44426f4cdaae35e69b9f3cecca
- Fixes a bug where a dropdown was partially hidden by the keyboard https://github.com/tuskyapp/Tusky/pull/4913
- Tusky side timeline filters apply to own posts again https://github.com/tuskyapp/Tusky/pull/4879
- Fixes a bug where media previews would flicker when interacting with a post https://github.com/tuskyapp/Tusky/pull/4971
- Tusky now ignores invalid publishing dates of preview cards that caused some posts not to load https://github.com/tuskyapp/Tusky/pull/4993

## v27.2

### Significant bug fixes

- The title of a hashtag tab now shows the actual hashtags again (instead of just "Hashtags") https://github.com/tuskyapp/Tusky/pull/4868
- Makes sure the background color of a dialogs is correct https://github.com/tuskyapp/Tusky/pull/4864
- Fixes an issue where Tusky would freeze while loading a timeline gap https://github.com/tuskyapp/Tusky/pull/4865

## v27.1

### New features and other improvements

- The width of the tab indicator has been increased https://github.com/tuskyapp/Tusky/pull/4849

### Significant bug fixes

- Improves rendering of some animated custom emojis https://github.com/tuskyapp/Tusky/pull/4281
- Fixes an issue where the input field for media descriptions was too small in some cases https://github.com/tuskyapp/Tusky/pull/4831
- Fixes an issue where hashtags at the end of posts were duplicated https://github.com/tuskyapp/Tusky/pull/4845
- Fixes an issue that prevented lists from being edited https://github.com/tuskyapp/Tusky/pull/4851

## v27.0

### New features and other improvements

- Tusky has been redesigned with Material 3 https://github.com/tuskyapp/Tusky/pull/4637 https://github.com/tuskyapp/Tusky/pull/4673
- Support for Notification Policies (Mastodon 4.3 feature) https://github.com/tuskyapp/Tusky/pull/4768
- Hashtags at the end of posts are now shown in a separate bar https://github.com/tuskyapp/Tusky/pull/4761
- Full support for folding devices https://github.com/tuskyapp/Tusky/pull/4689
- Improved post rendering in some edge cases https://github.com/tuskyapp/Tusky/pull/4650 https://github.com/tuskyapp/Tusky/pull/4672 https://github.com/tuskyapp/Tusky/pull/4723
- Descriptions can now be added to audio attachments https://github.com/tuskyapp/Tusky/pull/4711
- The screen keyboard now pops up automatically when opening a dialog that contains a textfield https://github.com/tuskyapp/Tusky/pull/4667

### Significant bug fixes

- fixes a bug where Tusky would drop your draft when switching apps https://github.com/tuskyapp/Tusky/pull/4685 https://github.com/tuskyapp/Tusky/pull/4813 https://github.com/tuskyapp/Tusky/pull/4818
- fixes a bug where Tusky would drop media that is being added to a post https://github.com/tuskyapp/Tusky/pull/4662
- fixes a bug that caused the login to fail in some cases https://github.com/tuskyapp/Tusky/pull/4704

## v26.2

### Significant bug fixes

- Fixes a bug where Tusky would not correctly switch between accounts https://github.com/tuskyapp/Tusky/pull/4636
- Fixes a crash when a status in a notification contains a reblog (happens when subscribed to a Friendica group) https://github.com/tuskyapp/Tusky/pull/4638
- Long video descriptions can no longer cover the video controls https://github.com/tuskyapp/Tusky/pull/4632
- Fixes a bug where Tusky's URL detection algorithm was different from Mastodon's https://github.com/tuskyapp/Tusky/pull/4642

## v26.1

### New features and other improvements

- The "Reply privacy" account preference now has two additional options: "Match default post privacy" and "Direct". "Match default post privacy" is the default for new accounts. https://github.com/tuskyapp/Tusky/pull/4568
- Tusky now includes ISRG root certificates to keep working on Android 7 and servers that use Let's Encrypt. https://github.com/tuskyapp/Tusky/pull/4609
- The soft keyboard will now be hidden after performing a search. https://github.com/tuskyapp/Tusky/pull/4578

### Significant bug fixes

- Fixes a bug where Tusky sometimes mixes up timelines and/or notifications of accounts. https://github.com/tuskyapp/Tusky/pull/4577 https://github.com/tuskyapp/Tusky/pull/4599
- Fixes two bugs where Tusky would not provide the translation option even though the server is configured correctly. https://github.com/tuskyapp/Tusky/pull/4560 https://github.com/tuskyapp/Tusky/pull/4590
- Fixes a rare bug where Tusky would sometimes randomly crash on startup. https://github.com/tuskyapp/Tusky/pull/4569
- Fixes a bug where the timeline would randomly jump to the position of the last clicked "show more" placeholder when "Reading order" was set to "Oldest first". https://github.com/tuskyapp/Tusky/pull/4619

## v26.0

### New features and other improvements

- The blue primary color that previously was the same for all themes is now slightly lighter in the dark theme and darker in the light theme for better contrast.
  Consequently, the color that is used on top of the primary color (e.g. on buttons) is now dark instead of white in the dark theme. [PR#3921](https://github.com/tuskyapp/Tusky/pull/3921) [PR#4507](https://github.com/tuskyapp/Tusky/pull/4507)
- New account preference "default reply privacy".
  Note that in contrast to the "default post privacy" this setting will not be synced with the server as Mastodon does not have this feature. [PR#4496](https://github.com/tuskyapp/Tusky/pull/4496)
- New preference "Show confirmation before following" [PR#4445](https://github.com/tuskyapp/Tusky/pull/4445)
- The notification tab is now cached on the device for better offline behavior.
  Since it shares the cache with the home timeline, interactions with posts will now sync between those tabs more often than before. [PR#4026](https://github.com/tuskyapp/Tusky/pull/4026)
- Tusky will now only make one call to the server to check which version of the filters api is supported and cache the result instead of everytime filters are needed. [PR#4539](https://github.com/tuskyapp/Tusky/pull/4539)
- The "Hide compose button while scrolling" preference, which had the main purpose of making content behind the button accessible, has been removed and bottom padding added to all lists that could be obscured by buttons. [PR#4486](https://github.com/tuskyapp/Tusky/pull/4486)
- When viewing media of a translated post the media descriptions will now also be translated [PR#4463](https://github.com/tuskyapp/Tusky/pull/4463)
- The custom emojis in the emoji picker are now sorted by category [PR#4533](https://github.com/tuskyapp/Tusky/pull/4533)
- Various internal refactorings to improve performance and maintainability.
  [PR#4515](https://github.com/tuskyapp/Tusky/pull/4515)
  [PR#4502](https://github.com/tuskyapp/Tusky/pull/4502)
  [PR#4472](https://github.com/tuskyapp/Tusky/pull/4472)
  [PR#4470](https://github.com/tuskyapp/Tusky/pull/4470)
  [PR#4443](https://github.com/tuskyapp/Tusky/pull/4443)
  [PR#4441](https://github.com/tuskyapp/Tusky/pull/4441)
  [PR#4461](https://github.com/tuskyapp/Tusky/pull/4461)
  [PR#4447](https://github.com/tuskyapp/Tusky/pull/4447)
  [PR#4411](https://github.com/tuskyapp/Tusky/pull/4411)
  [PR#4413](https://github.com/tuskyapp/Tusky/pull/4413)

### Significant bug fixes

- Posts with null media focus values will no longer cause Tusky to show an error [PR#4462](https://github.com/tuskyapp/Tusky/pull/4462)
- A lot of other bugfixes, mostly smaller display bugs
  [PR#4536](https://github.com/tuskyapp/Tusky/pull/4536)
  [PR#4537](https://github.com/tuskyapp/Tusky/pull/4537)
  [PR#4527](https://github.com/tuskyapp/Tusky/pull/4527)
  [PR#4521](https://github.com/tuskyapp/Tusky/pull/4521)
  [PR#4525](https://github.com/tuskyapp/Tusky/pull/4525)
  [PR#4518](https://github.com/tuskyapp/Tusky/pull/4518)
  [PR#4514](https://github.com/tuskyapp/Tusky/pull/4514)
  [PR#4491](https://github.com/tuskyapp/Tusky/pull/4491)
  [PR#4490](https://github.com/tuskyapp/Tusky/pull/4490)
  [PR#4474](https://github.com/tuskyapp/Tusky/pull/4474)
  [PR#4436](https://github.com/tuskyapp/Tusky/pull/4436)

## v25.2

### Significant bug fixes

- Fixes a bug that could sometimes crash Tusky when rotating the screen while viewing an account list [PR#4430](https://github.com/tuskyapp/Tusky/pull/4430)
- Fixes a bug that could crash Tusky at startup under certain conditions [PR#4431](https://github.com/tuskyapp/Tusky/pull/4431)
- Fixes a bug that caused Tusky to crash when custom emojis with too large dimensions were loaded [PR#4429](https://github.com/tuskyapp/Tusky/pull/4429)
- Makes Tusky work again with Iceshrimp by working around a quirk in their API implementation [PR#4426](https://github.com/tuskyapp/Tusky/pull/4426)
- Fixes a bug that made translations not work on some servers [PR#4422](https://github.com/tuskyapp/Tusky/pull/4422)

## v25.1

### Significant bug fixes

- Fixed two crashes at startup introduced in 25.0 [PR#4415](https://github.com/tuskyapp/Tusky/pull/4415) [PR#4417](https://github.com/tuskyapp/Tusky/pull/4417)

## v25.0

### New features and other improvements

- Added support for the [Mastodon translation api](https://docs.joinmastodon.org/methods/statuses/#translate).
  You can now find a new option "translate" in the three-dot-menu on posts that are not in your display language when your server supports the translation api.
  Support is determined by checking the `configuration.translation.enabled` attribute of the `/api/v2/instance` endpoint.
  [PR#4307](https://github.com/tuskyapp/Tusky/pull/4307)
- The language of a post is now shown in the metadata section of the detail post view, if it is available. [PR#4127](https://github.com/tuskyapp/Tusky/pull/4127)
- The transitions between screens have been changed to feel faster and align more with default Android transitions. [PR#4285](https://github.com/tuskyapp/Tusky/pull/4285)
- The post statistic section below the detail post view is now always shown to prevent layout shifts on the first like or boost.
  [PR#4205](https://github.com/tuskyapp/Tusky/pull/4205) [PR#4260](https://github.com/tuskyapp/Tusky/pull/4260)
- The filters for boosts/replies/self-boosts in the home timeline have moved from general preferences to account specific preferences. [PR#4115](https://github.com/tuskyapp/Tusky/pull/4115)
- The json parsing library has been migrated from Gson to Moshi. This change will make Tusky no longer crash on unexpected server responses. [PR#4309](https://github.com/tuskyapp/Tusky/pull/4309)
- Small layout improvements to the header of the profile view [PR#4375](https://github.com/tuskyapp/Tusky/pull/4375) [PR#4371](https://github.com/tuskyapp/Tusky/pull/4371)
- support for Android 14 Upside Down Cake [PR#4224](https://github.com/tuskyapp/Tusky/pull/4224)
- Various internal refactorings to improve performance and maintainability.
  [PR#4269](https://github.com/tuskyapp/Tusky/pull/4269)
  [PR#4290](https://github.com/tuskyapp/Tusky/pull/4290)
  [PR#4291](https://github.com/tuskyapp/Tusky/pull/4291)
  [PR#4296](https://github.com/tuskyapp/Tusky/pull/4296)
  [PR#4364](https://github.com/tuskyapp/Tusky/pull/4364)
  [PR#4366](https://github.com/tuskyapp/Tusky/pull/4366)
  [PR#4372](https://github.com/tuskyapp/Tusky/pull/4372)
  [PR#4356](https://github.com/tuskyapp/Tusky/pull/4356)
  [PR#4348](https://github.com/tuskyapp/Tusky/pull/4348)
  [PR#4339](https://github.com/tuskyapp/Tusky/pull/4339)
  [PR#4337](https://github.com/tuskyapp/Tusky/pull/4337)
  [PR#4336](https://github.com/tuskyapp/Tusky/pull/4336)
  [PR#4330](https://github.com/tuskyapp/Tusky/pull/4330)
  [PR#4235](https://github.com/tuskyapp/Tusky/pull/4235)
  [PR#4081](https://github.com/tuskyapp/Tusky/pull/4081)

### Significant bug fixes

- The setting to hide the notification filter bar that was accidentally removed is back. [PR#4225](https://github.com/tuskyapp/Tusky/pull/4225)
- The profile picture in the bottom navigation bar now has the correct content description. [PR#4400](https://github.com/tuskyapp/Tusky/pull/4400)

## v24.1

- The screen will stay on again while a video is playing. [PR#4168](https://github.com/tuskyapp/Tusky/pull/4168)
- A memory leak has been fixed. This should improve stability and performance. [PR#4150](https://github.com/tuskyapp/Tusky/pull/4150) [PR#4153](https://github.com/tuskyapp/Tusky/pull/4153)
- Emojis are now correctly counted as 1 character when composing a post. [PR#4152](https://github.com/tuskyapp/Tusky/pull/4152)
- Fixed a crash when text was selected on some devices. [PR#4166](https://github.com/tuskyapp/Tusky/pull/4166)
- The icons in the help texts of empty timelines will now always be correctly
  aligned. [PR#4179](https://github.com/tuskyapp/Tusky/pull/4179)
- Fixed ANR caused by direct message badge [PR#4182](https://github.com/tuskyapp/Tusky/pull/4182)

## v24.0

### New features and other improvements

- The number of tabs that can be configured is no longer limited. [PR#4058](https://github.com/tuskyapp/Tusky/pull/4058)
- Blockquotes and code blocks in posts now look nicer [PR#4090](https://github.com/tuskyapp/Tusky/pull/4090) [PR#4091](https://github.com/tuskyapp/Tusky/pull/4091)
- The old behavior of the notification tab (pre Tusky 22.0) has been restored. [PR#4015](https://github.com/tuskyapp/Tusky/pull/4015)
- Role badges are now shown on profiles (Mastodon 4.2 feature). [PR#4029](https://github.com/tuskyapp/Tusky/pull/4029)
- The video player has been upgraded to Google Jetpack Media3; video compatibility should be improved, and you can now adjust playback speed. [PR#3857](https://github.com/tuskyapp/Tusky/pull/3857)
- New theme option to use the black theme when following the system design. [PR#3957](https://github.com/tuskyapp/Tusky/pull/3957)
- Following the system design is now the default theme setting. [PR#3813](https://github.com/tuskyapp/Tusky/pull/3957)
- A new view to see trending posts is available both in the menu and as custom tab. [PR#4007](https://github.com/tuskyapp/Tusky/pull/4007)
- A new option to hide self boosts has been added. [PR#4101](https://github.com/tuskyapp/Tusky/pull/4101)
- The `api/v2/instance` endpoint is now supported. [PR#4062](https://github.com/tuskyapp/Tusky/pull/4062)
- New settings for lists:
    - Hide from the home timeline [PR#3932](https://github.com/tuskyapp/Tusky/pull/3932)
    - Decide which replies should be shown in the list [PR#4072](https://github.com/tuskyapp/Tusky/pull/4072)
- The oldest supported Android version is now Android 7 Nougat [PR#4014](https://github.com/tuskyapp/Tusky/pull/4014)

### Significant bug fixes

- **Empty trends no longer causes Tusky to crash**, [PR#3853](https://github.com/tuskyapp/Tusky/pull/3853)


## v23.0

### New features and other improvements

- **New preference to scale UI text**, [PR#3248](https://github.com/tuskyapp/Tusky/pull/3248) by [@nikclayton](https://mastodon.social/@nikclayton)

### Significant bug fixes

- **Save account information correctly**, [PR#3720](https://github.com/tuskyapp/Tusky/pull/3720) by [@connyduck](https://chaos.social/@ConnyDuck)
  - If you were logged in with multiple accounts it was possible to switch accounts in a way that the UI showed the new account, but database operations were happening using the old account.
- **"pull" notifications on devices running Android versions <= 11**, [PR#3649](https://github.com/tuskyapp/Tusky/pull/3649) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Pull notifications (i.e., not using ntfy.sh) could silently fail on devices running Android 11 and below
- **Work around Android bug where text fields could "forget" they can copy/paste**, [PR#3707](https://github.com/tuskyapp/Tusky/pull/3707) by [@nikclayton](https://mastodon.social/@nikclayton)
- **Viewing "diffs" in edit history will not extend off screen edge**, [PR#3431](https://github.com/tuskyapp/Tusky/pull/3431) by [@nikclayton](https://mastodon.social/@nikclayton)
- **Don't crash if your server has no post edit history**, [PR#3747](https://github.com/tuskyapp/Tusky/pull/3747) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Your Mastodon server might know that a post has been edited, but not know the details of those edits. Trying to view the history of those statuses no longer crashes.
- **Add a "Delete" button when editing a filter**, [PR#3553](https://github.com/tuskyapp/Tusky/pull/3553) by [@Tak](https://mastodon.gamedev.place/@Tak)
- **Show non-square emoji correctly**, [PR#3711](https://github.com/tuskyapp/Tusky/pull/3711) by [@connyduck](https://chaos.social/@ConnyDuck)
- **Potential crash when editing profile fields**, [PR#3808](https://github.com/tuskyapp/Tusky/pull/3808) by [@nikclayton](https://mastodon.social/@nikclayton)
- **Oversized context menu when editing image descriptions**, [PR#3787](https://github.com/tuskyapp/Tusky/pull/3787) by [@connyduck](https://chaos.social/@ConnyDuck)

## v23.0 beta 2

### Significant bug fixes

- **Potential crash when editing profile fields**, [PR#3808](https://github.com/tuskyapp/Tusky/pull/3808) by [@nikclayton](https://mastodon.social/@nikclayton)
- **Oversized context menu when editing image descriptions**, [PR#3787](https://github.com/tuskyapp/Tusky/pull/3787) by [@connyduck](https://chaos.social/@ConnyDuck)

## v23.0 beta 1

### New features and other improvements

- **New preference to scale UI text**, [PR#3248](https://github.com/tuskyapp/Tusky/pull/3248) by [@nikclayton](https://mastodon.social/@nikclayton)

### Significant bug fixes

- **Save account information correctly**, [PR#3720](https://github.com/tuskyapp/Tusky/pull/3720) by [@connyduck](https://chaos.social/@ConnyDuck)
  - If you were logged in with multiple accounts it was possible to switch accounts in a way that the UI showed the new account, but database operations were happening using the old account.
- **"pull" notifications on devices running Android versions <= 11**, [PR#3649](https://github.com/tuskyapp/Tusky/pull/3649) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Pull notifications (i.e., not using ntfy.sh) could silently fail on devices running Android 11 and below
- **Work around Android bug where text fields could "forget" they can copy/paste**, [PR#3707](https://github.com/tuskyapp/Tusky/pull/3707) by [@nikclayton](https://mastodon.social/@nikclayton)
- **Viewing "diffs" in edit history will not extend off screen edge**, [PR#3431](https://github.com/tuskyapp/Tusky/pull/3431) by [@nikclayton](https://mastodon.social/@nikclayton)
- **Don't crash if your server has no post edit history**, [PR#3747](https://github.com/tuskyapp/Tusky/pull/3747) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Your Mastodon server might know that a post has been edited, but not know the details of those edits. Trying to view the history of those statuses no longer crashes.
- **Add a "Delete" button when editing a filter**, [PR#3553](https://github.com/tuskyapp/Tusky/pull/3553) by [@Tak](https://mastodon.gamedev.place/@Tak)
- **Show non-square emoji correctly**, [PR#3711](https://github.com/tuskyapp/Tusky/pull/3711) by [@connyduck](https://chaos.social/@ConnyDuck)

## v22.0

### New features and other improvements

- **View trending hashtags**, [PR#3149](https://github.com/tuskyapp/Tusky/pull/3149) by [@knossos](https://fosstodon.org/@knossos)
  - View trending hashtags from the side menu, or by adding them to a new tab.
- **Edit image description and focus point**, [PR#3215](https://github.com/tuskyapp/Tusky/pull/3215) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Edit image descriptions and focus points when editing posts.
- **View profile banner images**, [PR#3274](https://github.com/tuskyapp/Tusky/pull/3274) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Tap the banner image on any profile to view it full size, save, share, etc.
- **Follow new hashtags**, [PR#3275](https://github.com/tuskyapp/Tusky/pull/3275) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Follow new hashtags from the "Followed hashtags" screen.
- **Better ordering when selecting languages**, [PR#3293](https://github.com/tuskyapp/Tusky/pull/3293) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Tusky will prioritise the language of the post being replied to, your default posting language, configured Tusky languages, and configured system languages when ordering the list of languages to post in.
- **"Load more" break is more prominent**, [PR#3376](https://github.com/tuskyapp/Tusky/pull/3376) by [@lakoja](https://freiburg.social/@lakoja)
  - Adjusted the design so the "Load more" break in a timeline is more obvious.
- **Add "Refresh" menu**, [PR#3121](https://github.com/tuskyapp/Tusky/pull/3121) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Tusky timelines can now be refreshed from a menu as well as swiping, making this accessible to assistive devices.
- **Notifications timeline improvements**, [PR#3159](https://github.com/tuskyapp/Tusky/pull/3159) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Notifications no longer need to "Load more", they are loaded automatically as you scroll.
  - Errors when interacting with notifications are displayed to the user, with a "Retry" option.
- **Show the difference between versions of a post**, [PR#3314](https://github.com/tuskyapp/Tusky/pull/3314) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Viewing the edits to a post highlights the differences (text that was added or deleted) between the different versions.
- **Support Mastodon v4 filters**, [PR#3188](https://github.com/tuskyapp/Tusky/pull/3188) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Mastodon v4 introduced additional [filtering controls](https://docs.joinmastodon.org/user/moderating/#filters).
- **Option to show post statistics in the timeline**, [PR#3413](https://github.com/tuskyapp/Tusky/pull/3413)
  - Tusky can now (optionally) show the number of replies, reposts, and favourites a post has received, in the timeline.
- **Expanded tappable area for links, hashtags, and mentions in a post**, [PR#3382](https://github.com/tuskyapp/Tusky/pull/3382) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Links, hashtags, and mentions in a post now react to taps that are a little above, below, or to the side of the tappable text, making them more accessible.

### Significant bug fixes

- **Remember selected tab and position**, [PR#3255](https://github.com/tuskyapp/Tusky/pull/3255) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Changing your tab settings (adding, removing, re-ordering) remembers your reading position in those tabs.
- **Show player controls during audio playback**, [PR#3286](https://github.com/tuskyapp/Tusky/pull/3286) by [@EricFrohnhoefer](https://mastodon.social/@EricFrohnhoefer)
  - A regression from v21.0 where the media player controls could not be used.
- **Keep notifications until read**, [PR#3312](https://github.com/tuskyapp/Tusky/pull/3312) by [@lakoja](https://freiburg.social/@lakoja)
  - Opening Tusky would dismiss all active Tusky Android notifications.
- **Fix copying URLs at the end of a post**, [PR#3380](https://github.com/tuskyapp/Tusky/pull/3380) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Copying a URL from the end of a post could include an extra Unicode whitespace character, making the URL unusable as is.
- **Correctly display mixed RTL and LTR text in profiles**, [PR#3328](https://github.com/tuskyapp/Tusky/pull/3328) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Profile text that contained a mix of right-to-left and left-to-right writing directions would display incorrectly.
- **Stop showing duplicates of edited posts in threads**, [PR#3377](https://github.com/tuskyapp/Tusky/pull/3377) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Editing a post in thread view would show the old and new version of the post in the thread.
- **Correct post length calculation**, [PR#3392](https://github.com/tuskyapp/Tusky/pull/3392) by [@nikclayton](https://mastodon.social/@nikclayton)
  - In a post that mentioned a user (e.g., `@tusky@mastodon.social`) Tusky was incorrectly including the `@mastodon.social` part when calculating the post's length, leading to incorrect "This post is too long" errors.
- **Always publish image captions**, [PR#3421](https://github.com/tuskyapp/Tusky/pull/3421) by [@lakoja](https://freiburg.social/@lakoja)
  - Finishing editing an image caption before the image had finished loading would lose the caption.
- **Clicking "Compose" from a notification would set the wrong account**, [PR#3688](https://github.com/tuskyapp/Tusky/pull/3688)

## v22.0 beta 7

### Significant bug fixes

- **Fetch all outstanding Mastodon notifications when creating Android notifications**, [PR#3700](https://github.com/tuskyapp/Tusky/pull/3700)
- **Clicking "Compose" from a notification would set the wrong account**, [PR#3688](https://github.com/tuskyapp/Tusky/pull/3688)
- **Ensure "last read notification ID" is saved to the correct account**, [PR#3697](https://github.com/tuskyapp/Tusky/pull/3697)

## v22.0 beta 6

### Significant bug fixes

- **Save reading position in the Notifications tab more frequently**, [PR#3685](https://github.com/tuskyapp/Tusky/pull/3685)

## v22.0 beta 5

## Significant bug fixes

- **Rolled back APNG library to fix broken animated emojis**, [PR#3676](https://github.com/tuskyapp/Tusky/pull/3676)
- **Save local copy of notification marker in case server does not support the API**, [PR#3672](https://github.com/tuskyapp/Tusky/pull/3672)

## v22.0 beta 4

### Significant bug fixes

- **Fixed repeated fetch of notifications if configured with multiple accounts**, [PR#3660](https://github.com/tuskyapp/Tusky/pull/3660)

## v22.0 beta 3

### Significant bug fixes

- **Fixed crash when viewing a thread**, [PR#3622](https://github.com/tuskyapp/Tusky/pull/3622)
- **Fixed crash processing Mastodon filters**, [PR#3634](https://github.com/tuskyapp/Tusky/pull/3634)
- **Links in bios of follow/follow request notifications are clickable**, [PR#3646](https://github.com/tuskyapp/Tusky/pull/3646)
- **Android Notifications updates**, [PR#3636](https://github.com/tuskyapp/Tusky/pull/3626)
  - Android notification for a Mastodon notification should only be shown once
  - Android notifications are grouped by Mastodon notification type (follow, mention, boost, etc)
  - Potential for missing notifications has been removed

## v22.0 beta 2

### Significant bug fixes

- **Improved notification loading speed**, [PR#3598](https://github.com/tuskyapp/Tusky/pull/3598)
- **Restore showing 0/1/1+ for replies**, [PR#3590](https://github.com/tuskyapp/Tusky/pull/3590)
- **Show filter titles, not filter keywords, on filtered posts**, [PR#3589](https://github.com/tuskyapp/Tusky/pull/3589)
- **Fixed a bug where opening a status could open an unrelated link**, [PR#3600](https://github.com/tuskyapp/Tusky/pull/3600)
- **Show "Add" button in correct place when there are no filters**, [PR#3561](https://github.com/tuskyapp/Tusky/pull/3561)
- **Fixed assorted crashes**

## v22.0 beta 1

### New features and other improvements

- **View trending hashtags**, [PR#3149](https://github.com/tuskyapp/Tusky/pull/3149) by [@knossos](https://fosstodon.org/@knossos)
  - View trending hashtags from the side menu, or by adding them to a new tab.
- **Edit image description and focus point**, [PR#3215](https://github.com/tuskyapp/Tusky/pull/3215) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Edit image descriptions and focus points when editing posts.
- **View profile banner images**, [PR#3274](https://github.com/tuskyapp/Tusky/pull/3274) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Tap the banner image on any profile to view it full size, save, share, etc.
- **Follow new hashtags**, [PR#3275](https://github.com/tuskyapp/Tusky/pull/3275) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Follow new hashtags from the "Followed hashtags" screen.
- **Better ordering when selecting languages**, [PR#3293](https://github.com/tuskyapp/Tusky/pull/3293) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Tusky will prioritise the language of the post being replied to, your default posting language, configured Tusky languages, and configured system languages when ordering the list of languages to post in.
- **"Load more" break is more prominent**, [PR#3376](https://github.com/tuskyapp/Tusky/pull/3376) by [@lakoja](https://freiburg.social/@lakoja)
  - Adjusted the design so the "Load more" break in a timeline is more obvious.
- **Add "Refresh" menu**, [PR#3121](https://github.com/tuskyapp/Tusky/pull/3121) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Tusky timelines can now be refreshed from a menu as well as swiping, making this accessible to assistive devices.
- **Notifications timeline improvements**, [PR#3159](https://github.com/tuskyapp/Tusky/pull/3159) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Notifications no longer need to "Load more", they are loaded automatically as you scroll.
  - Errors when interacting with notifications are displayed to the user, with a "Retry" option.
- **Show the difference between versions of a post**, [PR#3314](https://github.com/tuskyapp/Tusky/pull/3314) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Viewing the edits to a post highlights the differences (text that was added or deleted) between the different versions.
- **Support Mastodon v4 filters**, [PR#3188](https://github.com/tuskyapp/Tusky/pull/3188) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Mastodon v4 introduced additional [filtering controls](https://docs.joinmastodon.org/user/moderating/#filters).
- **Option to show post statistics in the timeline**, [PR#3413](https://github.com/tuskyapp/Tusky/pull/3413)
  - Tusky can now (optionally) show the number of replies, reposts, and favourites a post has received, in the timeline.
- **Expanded tappable area for links, hashtags, and mentions in a post**, [PR#3382](https://github.com/tuskyapp/Tusky/pull/3382) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Links, hashtags, and mentions in a post now react to taps that are a little above, below, or to the side of the tappable text, making them more accessible.

### Significant bug fixes

- **Remember selected tab and position**, [PR#3255](https://github.com/tuskyapp/Tusky/pull/3255) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Changing your tab settings (adding, removing, re-ordering) remembers your reading position in those tabs.
- **Show player controls during audio playback**, [PR#3286](https://github.com/tuskyapp/Tusky/pull/3286) by [@EricFrohnhoefer](https://mastodon.social/@EricFrohnhoefer)
  - A regression from v21.0 where the media player controls could not be used.
- **Keep notifications until read**, [PR#3312](https://github.com/tuskyapp/Tusky/pull/3312) by [@lakoja](https://freiburg.social/@lakoja)
  - Opening Tusky would dismiss all active Tusky Android notifications.
- **Fix copying URLs at the end of a post**, [PR#3380](https://github.com/tuskyapp/Tusky/pull/3380) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Copying a URL from the end of a post could include an extra Unicode whitespace character, making the URL unusable as is.
- **Correctly display mixed RTL and LTR text in profiles**, [PR#3328](https://github.com/tuskyapp/Tusky/pull/3328) by [@nikclayton](https://mastodon.social/@nikclayton)
  - Profile text that contained a mix of right-to-left and left-to-right writing directions would display incorrectly.
- **Stop showing duplicates of edited posts in threads**, [PR#3377](https://github.com/tuskyapp/Tusky/pull/3377) by [@Tak](https://mastodon.gamedev.place/@Tak)
  - Editing a post in thread view would show the old and new version of the post in the thread.
- **Correct post length calculation**, [PR#3392](https://github.com/tuskyapp/Tusky/pull/3392) by [@nikclayton](https://mastodon.social/@nikclayton)
  - In a post that mentioned a user (e.g., `@tusky@mastodon.social`) Tusky was incorrectly including the `@mastodon.social` part when calculating the post's length, leading to incorrect "This post is too long" errors.
- **Always publish image captions**, [PR#3421](https://github.com/tuskyapp/Tusky/pull/3421) by [@lakoja](https://freiburg.social/@lakoja)
  - Finishing editing an image caption before the image had finished loading would lose the caption.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

Thanks for your interest in contributing to Tusky! Here are some informations to help you get started.

If you have any questions, don't hesitate to open an issue or join our [development chat on Matrix](https://riot.im/app/#/room/#Tusky:matrix.org).

## Contributing translations

Translations are managed on our [Weblate](https://weblate.tusky.app/projects/tusky/tusky/). You can create an account and translate texts through the interface, no coding knowledge required.
To add a new language, click on the 'Start a new translation' button on at the bottom of the page.

- Use gender-neutral language
- Address users informally (e.g. in German "du" and never "Sie")

## Contributing code

### Prerequisites
You should have a general understanding of Android development and Git.

### Architecture
We try to follow the [Guide to app architecture](https://developer.android.com/topic/architecture).

### Kotlin
Tusky was originally written in Java, but is in the process of migrating to Kotlin. All new code must be written in Kotlin.
We try to follow the [Kotlin Style Guide](https://developer.android.com/kotlin/style-guide) and format the code according to the default [ktlint codestyle](https://github.com/pinterest/ktlint).
You can check the codestyle by running `./gradlew ktlintCheck lint`. This will fail if you have any errors, and produces a detailed report which also lists warnings.
We intentionally have very few hard linting errors, so that new contributors can focus on what they want to achieve instead of fighting the linter.

### Text
All English text that will be visible to users must be put in `app/src/main/res/values/strings.xml` so it is translateable into other languages.
Try to keep texts friendly and concise.
If there is untranslatable text that you don't want to keep as a string constant in Kotlin code, you can use the string resource file `app/src/main/res/values/donottranslate.xml`.

### Viewbinding
We use [Viewbinding](https://developer.android.com/topic/libraries/view-binding) to reference views. No contribution using another mechanism will be accepted.
There are useful extensions in `src/main/java/com/keylesspalace/tusky/util/ViewExtensions.kt` that make working with viewbinding easier.

### Themes
There are three themes in the app, so any visual changes should be checked with each of them to ensure they look appropriate no matter which theme is selected. Usually, you can use existing color attributes like `?attr/colorPrimary` and `?attr/textColorSecondary`.

### Icons
All icons are from the rounded variant of the Material Symbols icon set with weight 400 and grade 0.
New icons can be found [here](https://fonts.google.com/icons?icon.style=Rounded&icon.size=24).
Usually we prefer outlined icons, but there are cases where a filled one is a better choice.
If the icon needs to have an active/inactive state it is a good idea to use the outlined icon for the inactive and the filled one for the active state.

Icons should be imported as vector drawables and named `ic_icon_name_sizedp_modifier.xml`, e.g. `ic_home_24dp` or `ic_notifications_24dp_filled`.

### Accessibility
We try to make Tusky as accessible as possible for as many people as possible. Please make sure that all touch targets are at least 48dpx48dp in size, Text has sufficient contrast and images or icons have a image description. See [this guide](https://developer.android.com/guide/topics/ui/accessibility/apps) for more information.

### Supported servers
Tusky is primarily a Mastodon client and aims to always support the newest Mastodon version. Other platforms implementing the Mastodon API, e.g. Akkoma, GoToSocial or Pixelfed should also work with Tusky, but no special effort is made to support their quirks or additional features.

### Payment Policy
Our payment policy may be viewed [here](https://github.com/tuskyapp/Tusky/blob/develop/doc/PaymentPolicy.md).

## Troubleshooting / FAQ

- Tusky should be built with the newest version of Android Studio.
- Tusky comes with two sets of build variants, "blue" and "green", which can be installed simultaneously and are distinguished by the colors of their icons. Green is intended for local development and testing, whereas blue is for releases.

## Resources
- [Mastodon API documentation](https://docs.joinmastodon.org/api/)

## AI policy
Tusky does not want any contributions, code or otherwise, created with so-called generative AI tools. Please only submit your own work.


================================================
FILE: LICENSE.txt
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.


================================================
FILE: README.md
================================================
This repository has moved to Codeberg: https://codeberg.org/tusky/Tusky

# Tusky

<img src="/fastlane/metadata/android/en-US/images/icon.png" width="120" height="120"/>

[<img src="/assets/fdroid_badge.png" alt="Get it on F-Droid" height="80" />](https://f-droid.org/repository/browse/?fdid=com.keylesspalace.tusky)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" alt="Get it on Google Play" height="80" />](https://play.google.com/store/apps/details?id=com.keylesspalace.tusky&utm_source=github&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1)


================================================
FILE: app/build.gradle
================================================
import app.cash.licensee.SpdxId

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.google.ksp)
    alias(libs.plugins.hilt.android)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.parcelize)
    alias(libs.plugins.licensee)
}

apply from: 'getGitSha.gradle'

final def gitSha = ext.getGitSha()

// The app name
final def APP_NAME = "Tusky"
// The application id. Must be unique, e.g. based on your domain
final def APP_ID = "com.keylesspalace.tusky"
// url of a custom app logo. Recommended size at least 600x600. Keep empty to use the Tusky elephant friend.
final def CUSTOM_LOGO_URL = ""
// e.g. mastodon.social. Keep empty to not suggest any instance on the signup screen
final def CUSTOM_INSTANCE = ""
// link to your support account. Will be linked on the about page when not empty.
final def SUPPORT_ACCOUNT_URL = "https://mastodon.social/@Tusky"

android {
    compileSdk 36
    namespace "com.keylesspalace.tusky"
    defaultConfig {
        applicationId APP_ID
        namespace "com.keylesspalace.tusky"
        minSdk 24
        targetSdk 36
        versionCode 133
        versionName "29.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true

        resValue "string", "app_name", APP_NAME

        buildConfigField("String", "CUSTOM_LOGO_URL", "\"$CUSTOM_LOGO_URL\"")
        buildConfigField("String", "CUSTOM_INSTANCE", "\"$CUSTOM_INSTANCE\"")
        buildConfigField("String", "SUPPORT_ACCOUNT_URL", "\"$SUPPORT_ACCOUNT_URL\"")
    }
    buildTypes {
        debug {
            isDefault true
        }
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles 'proguard-rules.pro'

            kotlinOptions {
                freeCompilerArgs = [
                    "-Xno-param-assertions",
                    "-Xno-call-assertions",
                    "-Xno-receiver-assertions"
                ]
            }
        }
    }

    flavorDimensions += "color"
    productFlavors {
        blue {}
        green {
            resValue "string", "app_name", APP_NAME + " Test"
            applicationIdSuffix ".test"
            versionNameSuffix "-" + gitSha
            isDefault true
        }
    }

    lint {
        lintConfig file("lint.xml")
        // Regenerate by deleting the file and running `./gradlew app:lintGreenDebug`
        baseline = file("lint-baseline.xml")
    }

    buildFeatures {
        buildConfig true
        resValues true
        viewBinding true
    }

    testOptions {
        unitTests {
            returnDefaultValues = true
            includeAndroidResources = true
        }
        unitTests.all {
            systemProperty 'robolectric.logging.enabled', 'true'
            systemProperty 'robolectric.lazyload', 'ON'
        }
    }
    sourceSets {
        // workaround to have migrations available in unit tests
        // https://github.com/robolectric/robolectric/issues/3928#issuecomment-395309991
        debug.assets.srcDirs += files("$projectDir/schemas".toString())
    }

    // Exclude unneeded files added by libraries
    packagingOptions.resources.excludes += [
        'LICENSE_OFL',
        'LICENSE_UNICODE',
        'META-INF/androidx/**',
        'META-INF/NOTICE.md',
        'DebugProbesKt.bin'
    ]

    bundle {
        language {
            // bundle all languages in every apk so the dynamic language switching works
            enableSplit = false
        }
    }
    dependenciesInfo {
        includeInApk false
        includeInBundle false
    }
    applicationVariants.configureEach { variant ->
        variant.outputs.configureEach {
            outputFileName = "Tusky_${variant.versionName}_${variant.versionCode}_${gitSha}_" +
                "${variant.flavorName}_${buildType.name}.apk"
        }
    }
}

ksp {
    arg("room.schemaLocation", "$projectDir/schemas")
    arg("room.generateKotlin", "true")
    arg("room.incremental", "true")
}

licensee {
    allow(SpdxId.Apache_20)
    allow(SpdxId.MIT)
    allowUrl('https://github.com/AOMediaCodec/libavif/blob/master/LICENSE')
    allowUrl('https://www.bouncycastle.org/licence.html')
}

configurations {
    // JNI-only libraries don't play nicely with Robolectric
    // see https://github.com/tuskyapp/Tusky/pull/3367
    testImplementation.exclude group: "org.conscrypt", module: "conscrypt-android"
    testRuntime.exclude group: "org.conscrypt", module: "conscrypt-android"
}

// library versions are in PROJECT_ROOT/gradle/libs.versions.toml
dependencies {
    implementation libs.kotlinx.coroutines.android

    implementation libs.bundles.androidx
    implementation libs.bundles.room
    ksp libs.androidx.room.compiler

    implementation libs.android.material

    implementation libs.bundles.moshi
    ksp libs.moshi.kotlin.codegen

    implementation libs.bundles.retrofit
    implementation libs.networkresult.calladapter

    implementation libs.bundles.okhttp
    implementation libs.okio

    implementation libs.conscrypt.android

    implementation libs.bundles.glide
    ksp libs.glide.compiler

    implementation libs.hilt.android
    ksp libs.hilt.compiler
    implementation libs.androidx.hilt.work
    ksp libs.androidx.hilt.compiler

    implementation libs.sparkbutton

    implementation libs.touchimageview

    implementation libs.bundles.material.drawer

    implementation libs.image.cropper

    implementation libs.bundles.filemojicompat

    implementation libs.bouncycastle
    implementation libs.unified.push

    implementation libs.bundles.xmldiff

    testImplementation libs.androidx.test.junit
    testImplementation libs.robolectric
    testImplementation libs.bundles.mockito
    testImplementation libs.mockwebserver
    testImplementation libs.androidx.core.testing
    testImplementation libs.androidx.room.testing
    testImplementation libs.kotlinx.coroutines.test
    testImplementation libs.androidx.work.testing
    testImplementation libs.turbine
}


================================================
FILE: app/getGitSha.gradle
================================================
import org.gradle.api.provider.ValueSourceParameters
import javax.inject.Inject

// Must wrap this in a ValueSource in order to get well-defined fail behavior without confusing Gradle on repeat builds.
abstract class GitShaValueSource implements ValueSource<String, ValueSourceParameters.None> {
    @Inject abstract ExecOperations getExecOperations()

    @Override String obtain() {
        try {
            def output = new ByteArrayOutputStream()

            execOperations.exec {
                it.commandLine 'git', 'rev-parse', '--short=8', 'HEAD'
                it.standardOutput = output
            }
            return output.toString().trim()
        } catch (GradleException ignore) {
            // Git executable unavailable, or we are not building in a git repo. Fall through:
        }
        return "unknown"
    }
}

// Export closure
ext.getGitSha = {
    providers.of(GitShaValueSource) {}.get()
}


================================================
FILE: app/lint-baseline.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.9.2" type="baseline" client="gradle" dependencies="false" name="AGP (8.9.2)" variant="all" version="8.9.2">

    <issue
        id="GestureBackNavigation"
        message="If intercepting back events, this should be handled through the registration of callbacks on the window level; Please see https://developer.android.com/about/versions/13/features/predictive-back-gesture"
        errorLine1="            if (keyCode == KeyEvent.KEYCODE_BACK) {"
        errorLine2="                           ~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt"
            line="1235"
            column="28"/>
    </issue>

    <issue
        id="DefaultLocale"
        message="Implicitly using the default locale is a common source of bugs: Use `toUpperCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
        errorLine1="            sb.append(language.toUpperCase());"
        errorLine2="                               ~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java"
            line="102"
            column="32"/>
    </issue>

    <issue
        id="InlinedApi"
        message="Field requires API level 29 (current min is 24): `android.text.style.DynamicDrawableSpan#ALIGN_CENTER`"
        errorLine1="            builder.setSpan(ImageSpan(drawable, DynamicDrawableSpan.ALIGN_CENTER), builder.length - 2, builder.length - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)"
        errorLine2="                                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/viewdata/PollViewData.kt"
            line="74"
            column="49"/>
    </issue>

    <issue
        id="InlinedApi"
        message="Field requires API level 29 (current min is 24): `android.text.style.DynamicDrawableSpan#ALIGN_CENTER`"
        errorLine1="                builder.setSpan(ImageSpan(drawable, DynamicDrawableSpan.ALIGN_CENTER), index, index + iconName.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)"
        errorLine2="                                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/util/SpanUtils.kt"
            line="122"
            column="53"/>
    </issue>

    <issue
        id="InvalidPackage"
        message="Invalid package reference in org.bouncycastle:bcprov-jdk15on; not included in Android: `javax.naming.directory`. Referenced from `org.bouncycastle.jce.provider.CrlCache`.">
        <location
            file="$GRADLE_USER_HOME/caches/modules-2/files-2.1/org.bouncycastle/bcprov-jdk15on/1.70/4636a0d01f74acaf28082fb62b317f1080118371/bcprov-jdk15on-1.70.jar"/>
    </issue>

    <issue
        id="InvalidPackage"
        message="Invalid package reference in org.bouncycastle:bcprov-jdk15on; not included in Android: `javax.naming`. Referenced from `org.bouncycastle.jce.provider.X509LDAPCertStoreSpi`.">
        <location
            file="$GRADLE_USER_HOME/caches/modules-2/files-2.1/org.bouncycastle/bcprov-jdk15on/1.70/4636a0d01f74acaf28082fb62b317f1080118371/bcprov-jdk15on-1.70.jar"/>
    </issue>

    <issue
        id="InvalidPackage"
        message="Invalid package reference in org.pageseeder.diffx:pso-diffx; not included in Android: `javax.xml.stream.events`. Referenced from `org.pageseeder.diffx.load.XMLEventLoader`.">
        <location
            file="$GRADLE_USER_HOME/caches/modules-2/files-2.1/org.pageseeder.diffx/pso-diffx/1.1.2/4c1a9f04f2802b97a5ec1de2c241079b29044375/pso-diffx-1.1.2.jar"/>
    </issue>

    <issue
        id="InvalidPackage"
        message="Invalid package reference in org.pageseeder.diffx:pso-diffx; not included in Android: `javax.xml.stream`. Referenced from `org.pageseeder.diffx.format.StrictXMLDiffOutput`.">
        <location
            file="$GRADLE_USER_HOME/caches/modules-2/files-2.1/org.pageseeder.diffx/pso-diffx/1.1.2/4c1a9f04f2802b97a5ec1de2c241079b29044375/pso-diffx-1.1.2.jar"/>
    </issue>

    <issue
        id="PrivateResource"
        message="Overriding `@layout/exo_player_control_view` which is marked as private in androidx.media3:media3-ui:1.6.1. If deliberate, use tools:override=&quot;true&quot;, otherwise pick a different name.">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@color/exo_bottom_bar_background` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        android:background=&quot;@color/exo_bottom_bar_background&quot;"
        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="39"
            column="29"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_controls_padding` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        android:padding=&quot;@dimen/exo_styled_controls_padding&quot;"
        errorLine2="                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="41"
            column="26"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@layout/exo_player_control_rewind_button` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        &lt;include layout=&quot;@layout/exo_player_control_rewind_button&quot; />"
        errorLine2="                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="48"
            column="26"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@layout/exo_player_control_ffwd_button` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        &lt;include layout=&quot;@layout/exo_player_control_ffwd_button&quot; />"
        errorLine2="                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="54"
            column="26"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_bottom_bar_height` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        android:layout_height=&quot;@dimen/exo_styled_bottom_bar_height&quot;"
        errorLine2="                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="63"
            column="32"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_bottom_bar_margin_top` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        android:layout_marginTop=&quot;@dimen/exo_styled_bottom_bar_margin_top&quot;"
        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="64"
            column="35"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@color/exo_bottom_bar_background` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        android:background=&quot;@color/exo_bottom_bar_background&quot;"
        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="66"
            column="29"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_bottom_bar_time_padding` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="            android:paddingStart=&quot;@dimen/exo_styled_bottom_bar_time_padding&quot;"
        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="72"
            column="35"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_bottom_bar_time_padding` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="            android:paddingEnd=&quot;@dimen/exo_styled_bottom_bar_time_padding&quot;"
        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="73"
            column="33"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_bottom_bar_time_padding` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="            android:paddingLeft=&quot;@dimen/exo_styled_bottom_bar_time_padding&quot;"
        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="74"
            column="34"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_bottom_bar_time_padding` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="            android:paddingRight=&quot;@dimen/exo_styled_bottom_bar_time_padding&quot;"
        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="75"
            column="35"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_progress_layout_height` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        android:layout_height=&quot;@dimen/exo_styled_progress_layout_height&quot;"
        errorLine2="                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="141"
            column="32"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_progress_margin_bottom` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        android:layout_marginBottom=&quot;@dimen/exo_styled_progress_margin_bottom&quot;/>"
        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="143"
            column="38"/>
    </issue>

    <issue
        id="PrivateResource"
        message="The resource `@dimen/exo_styled_minimal_controls_margin_bottom` is marked as private in androidx.media3:media3-ui:1.6.1"
        errorLine1="        android:layout_marginBottom=&quot;@dimen/exo_styled_minimal_controls_margin_bottom&quot;"
        errorLine2="                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="149"
            column="38"/>
    </issue>

    <issue
        id="PluralsCandidate"
        message="Formatting %d followed by words (&quot;posts&quot;): This should probably be a plural rather than a string"
        errorLine1="    &lt;string name=&quot;notification_summary_report_format&quot;>%1$s · %2$d posts attached&lt;/string>"
        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/values/strings.xml"
            line="113"
            column="5"/>
    </issue>

    <issue
        id="PluralsCandidate"
        message="Formatting %d followed by words (&quot;and&quot;): This should probably be a plural rather than a string"
        errorLine1="    &lt;string name=&quot;pref_title_http_proxy_port_message&quot;>Port should be between %1$d and %2$d&lt;/string>"
        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/values/strings.xml"
            line="326"
            column="5"/>
    </issue>

    <issue
        id="PluralsCandidate"
        message="Formatting %d followed by words (&quot;others&quot;): This should probably be a plural rather than a string"
        errorLine1="    &lt;string name=&quot;notification_summary_large&quot;>%1$s, %2$s, %3$s and %4$d others&lt;/string>"
        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/values/strings.xml"
            line="397"
            column="5"/>
    </issue>

    <issue
        id="PluralsCandidate"
        message="Formatting %d followed by words (&quot;more&quot;): This should probably be a plural rather than a string"
        errorLine1="    &lt;string name=&quot;conversation_more_recipients&quot;>%1$s, %2$s and %3$d more&lt;/string>"
        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/values/strings.xml"
            line="578"
            column="5"/>
    </issue>

    <issue
        id="PluralsCandidate"
        message="Formatting %d followed by words (&quot;people&quot;): This should probably be a plural rather than a string"
        errorLine1="    &lt;string name=&quot;accessibility_talking_about_tag&quot;>%1$d people are talking about hashtag %2$s&lt;/string>"
        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/values/strings.xml"
            line="795"
            column="5"/>
    </issue>

    <issue
        id="PluralsCandidate"
        message="Formatting %d followed by words (&quot;people&quot;): This should probably be a plural rather than a string"
        errorLine1="    &lt;string name=&quot;notifications_from_people_you_may_know&quot;>Notifications from %1$d people you may know&lt;/string>"
        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/values/strings.xml"
            line="872"
            column="5"/>
    </issue>

    <issue
        id="DataExtractionRules"
        message="The attribute `android:allowBackup` is deprecated from Android 12 and higher and may be removed in future versions. Consider adding the attribute `android:dataExtractionRules` specifying an `@xml` resource which configures cloud backups and device transfers on Android 12 and higher."
        errorLine1="        android:allowBackup=&quot;false&quot;"
        errorLine2="                             ~~~~~">
        <location
            file="src/main/AndroidManifest.xml"
            line="15"
            column="30"/>
    </issue>

    <issue
        id="NotifyDataSetChanged"
        message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
        errorLine1="        accountFieldAdapter.notifyDataSetChanged()"
        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt"
            line="485"
            column="9"/>
    </issue>

    <issue
        id="NotifyDataSetChanged"
        message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
        errorLine1="        notifyDataSetChanged()"
        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/AccountFieldEditAdapter.kt"
            line="45"
            column="9"/>
    </issue>

    <issue
        id="NotifyDataSetChanged"
        message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
        errorLine1="        notifyDataSetChanged()"
        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/AccountFieldEditAdapter.kt"
            line="51"
            column="9"/>
    </issue>

    <issue
        id="NotifyDataSetChanged"
        message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
        errorLine1="        notifyDataSetChanged()"
        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt"
            line="175"
            column="9"/>
    </issue>

    <issue
        id="NotifyDataSetChanged"
        message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
        errorLine1="        notifyDataSetChanged()"
        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/PollAdapter.kt"
            line="64"
            column="9"/>
    </issue>

    <issue
        id="NotifyDataSetChanged"
        message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
        errorLine1="        notifyDataSetChanged()"
        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt"
            line="34"
            column="9"/>
    </issue>

    <issue
        id="NotifyDataSetChanged"
        message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
        errorLine1="        notifyDataSetChanged()"
        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt"
            line="54"
            column="9"/>
    </issue>

    <issue
        id="NotifyDataSetChanged"
        message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort."
        errorLine1="            notifyDataSetChanged()"
        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt"
            line="161"
            column="13"/>
    </issue>

    <issue
        id="NegativeMargin"
        message="Margin values should not be negative"
        errorLine1="        android:layout_marginStart=&quot;-14dp&quot;"
        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/res/layout/item_conversation.xml"
            line="277"
            column="9"/>
    </issue>

    <issue
        id="ReportShortcutUsage"
        message="Calling this method indicates use of dynamic shortcuts, but there are no calls to methods that track shortcut usage, such as `pushDynamicShortcut` or `reportShortcutUsed`. Calling these methods is recommended, as they track shortcut usage and allow launchers to adjust which shortcuts appear based on activation history. Please see https://developer.android.com/develop/ui/views/launch/shortcuts/managing-shortcuts#track-usage"
        errorLine1="            ShortcutManagerCompat.setDynamicShortcuts(context, shortcuts)"
        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt"
            line="101"
            column="13"/>
    </issue>

    <issue
        id="UseKtx"
        message="Use the KTX extension function `Context.withStyledAttributes` instead?"
        errorLine1="        val a = context.obtainStyledAttributes("
        errorLine2="                ^">
        <location
            file="src/main/java/com/keylesspalace/tusky/view/SliderPreference.kt"
            line="99"
            column="17"/>
    </issue>

    <issue
        id="ClickableViewAccessibility"
        message="Custom view ``ImageView`` has `setOnTouchListener` called on it but does not override `performClick`"
        errorLine1="            binding.imageView.setOnTouchListener { _, event ->"
        errorLine2="            ^">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt"
            line="95"
            column="13"/>
    </issue>

    <issue
        id="ClickableViewAccessibility"
        message="`onTouch` lambda should call `View#performClick` when a click is detected"
        errorLine1="            binding.imageView.setOnTouchListener { _, event ->"
        errorLine2="                                                 ^">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt"
            line="95"
            column="50"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="        &lt;ImageButton android:id=&quot;@id/exo_prev&quot;"
        errorLine2="         ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="45"
            column="10"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="        &lt;ImageButton android:id=&quot;@id/exo_play_pause&quot;"
        errorLine2="         ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="51"
            column="10"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="        &lt;ImageButton android:id=&quot;@id/exo_next&quot;"
        errorLine2="         ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="56"
            column="10"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="            &lt;ImageButton android:id=&quot;@id/exo_vr&quot;"
        errorLine2="             ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="96"
            column="14"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="            &lt;ImageButton android:id=&quot;@id/exo_shuffle&quot;"
        errorLine2="             ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="99"
            column="14"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="            &lt;ImageButton android:id=&quot;@id/exo_repeat_toggle&quot;"
        errorLine2="             ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="102"
            column="14"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="            &lt;ImageButton android:id=&quot;@id/exo_subtitle&quot;"
        errorLine2="             ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="105"
            column="14"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="            &lt;ImageButton android:id=&quot;@id/exo_settings&quot;"
        errorLine2="             ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="108"
            column="14"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="            &lt;ImageButton android:id=&quot;@id/exo_fullscreen&quot;"
        errorLine2="             ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="111"
            column="14"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="            &lt;ImageButton android:id=&quot;@id/exo_overflow_show&quot;"
        errorLine2="             ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="114"
            column="14"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="                &lt;ImageButton android:id=&quot;@id/exo_overflow_hide&quot;"
        errorLine2="                 ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="130"
            column="18"/>
    </issue>

    <issue
        id="ContentDescription"
        message="Missing `contentDescription` attribute on image"
        errorLine1="        &lt;ImageButton android:id=&quot;@id/exo_minimal_fullscreen&quot;"
        errorLine2="         ~~~~~~~~~~~">
        <location
            file="src/main/res/layout/exo_player_control_view.xml"
            line="154"
            column="10"/>
    </issue>

    <issue
        id="SetTextI18n"
        message="Do not concatenate text displayed with `setText`. Use resource string with placeholders."
        errorLine1="                    cardMetadata.setText(providerName + metadataJoiner + TimestampUtils.getRelativeTimeSpanString(context, card.getPublishedAt().getTime(), System.currentTimeMillis()));"
        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
        <location
            file="src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java"
            line="1135"
            column="42"/>
    </issue>

</issues>


================================================
FILE: app/lint.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright 2023 Tusky Contributors
  ~
  ~ This file is a part of Tusky.
  ~
  ~ This program is free software; you can redistribute it and/or modify it under the terms of the
  ~ GNU General Public License as published by the Free Software Foundation; either version 3 of the
  ~ License, or (at your option) any later version.
  ~
  ~ Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
  ~ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
  ~ Public License for more details.
  ~
  ~ You should have received a copy of the GNU General Public License along with Tusky; if not,
  ~ see <http://www.gnu.org/licenses>.
  -->

<lint>
    <!-- Missing translations are OK -->
    <issue id="MissingTranslation" severity="ignore" />

    <!-- Duplicate strings are OK. This can happen when e.g., "favourite" appears as both
         a noun and a verb -->
    <issue id="DuplicateStrings" severity="ignore" />

    <!-- Resource IDs used in viewbinding are incorrectly reported as unused,
         https://issuetracker.google.com/issues/204797401.

         Disable these for the time being. -->
    <issue id="UnusedIds" severity="ignore" />
    <issue id="UnusedResources" severity="ignore" />

    <!-- Logs are stripped in release builds. -->
    <issue id="LogConditional" severity="ignore" />

    <!-- Newer dependencies are handled by Renovate, and don't need a warning -->
    <issue id="GradleDependency" severity="ignore" />
    <issue id="NewerVersionAvailable" severity="ignore" />

    <!-- Typographical punctuation is not something we care about at the moment -->
    <issue id="TypographyQuotes" severity="ignore" />
    <issue id="TypographyDashes" severity="ignore" />
    <issue id="TypographyEllipsis" severity="ignore" />

    <!-- Translations come from external parties -->
    <issue id="MissingQuantity" severity="ignore" />
    <issue id="ImpliedQuantity" severity="ignore" />
    <!-- Most alleged typos are in translations -->
    <issue id="Typos" severity="ignore" />

    <!-- Basically all of our vectors are external -->
    <issue id="VectorPath" severity="ignore" />
    <issue id="Overdraw" severity="ignore" />

    <!-- Irrelevant api version warnings -->
    <issue id="OldTargetApi" severity="ignore" />
    <issue id="UnusedAttribute" severity="ignore" />

    <!-- We do not *want* all the text in the app to be selectable -->
    <issue id="SelectableText" severity="ignore" />

    <!-- This is heavily used by the viewbinding helper -->
    <issue id="SyntheticAccessor" severity="ignore" />

    <!-- We already have Renovate reminding us of new versions -->
    <issue id="AndroidGradlePluginVersion" severity="ignore" />

    <!-- Things we would actually question in a code review -->
    <issue id="MissingPermission" severity="error" />
    <issue id="InvalidPackage" severity="error" />
    <issue id="UseCompatLoadingForDrawables" severity="error" />
    <issue id="UseCompatTextViewDrawableXml" severity="error" />
    <issue id="Recycle" severity="error" />
    <issue id="KeyboardInaccessibleWidget" severity="error" />
    <issue id="UnknownNullness" severity="error" />

    <!-- Mark all other lint issues as warnings -->
    <issue id="all" severity="warning" />
</lint>


================================================
FILE: app/proguard-rules.pro
================================================
# GENERAL OPTIONS

-allowaccessmodification

# Preserve some attributes that may be required for reflection.
-keepattributes RuntimeVisible*Annotations, AnnotationDefault

# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
    native <methods>;
}

# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers,allowoptimization enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keepclassmembers class * implements android.os.Parcelable {
    public static final ** CREATOR;
}

# TUSKY SPECIFIC OPTIONS

# preserve line numbers for crash reporting
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile

# Bouncy Castle -- Keep EC
-keep class org.bouncycastle.jcajce.provider.asymmetric.EC$* { *; }
-keep class org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi$EC

# Preference fragments can be referenced by name, ensure they remain
# https://github.com/tuskyapp/Tusky/issues/3161
-keep class * extends androidx.preference.PreferenceFragmentCompat

# remove all logging from production apk
-assumenosideeffects class android.util.Log {
    public static *** getStackTraceString(...);
    public static *** d(...);
    public static *** w(...);
    public static *** v(...);
    public static *** i(...);
}
-assumenosideeffects class java.lang.String {
    public static java.lang.String format(...);
}

# remove some kotlin overhead
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
    static void checkNotNull(java.lang.Object);
    static void checkNotNull(java.lang.Object, java.lang.String);
    static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
    static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
    static void checkNotNullParameter(java.lang.Object, java.lang.String);
    static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
    static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
    static void throwUninitializedProperty(java.lang.String);
    static void throwUninitializedPropertyAccessException(java.lang.String);
}

# there is no need for edit mode in production builds, allow it to be pruned
-assumenosideeffects public class * extends android.view.View {
  boolean isInEditMode();
}
-assumevalues public class * extends android.view.View {
  boolean isInEditMode() return false;
}

-checkdiscard class com.keylesspalace.tusky.usecase.DeveloperToolsUseCase


================================================
FILE: app/schemas/com.keylesspalace.tusky.db.AppDatabase/10.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 10,
    "identityHash": "69e310ef98c0f305934d25e763ee0140",
    "entities": [
      {
        "tableName": "TootEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT, `urls` TEXT, `descriptions` TEXT, `contentWarning` TEXT, `inReplyToId` TEXT, `inReplyToText` TEXT, `inReplyToUsername` TEXT, `visibility` INTEGER)",
        "fields": [
          {
            "fieldPath": "uid",
            "columnName": "uid",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "text",
            "columnName": "text",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "urls",
            "columnName": "urls",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "descriptions",
            "columnName": "descriptions",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "contentWarning",
            "columnName": "contentWarning",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToId",
            "columnName": "inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToText",
            "columnName": "inReplyToText",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToUsername",
            "columnName": "inReplyToUsername",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "visibility",
            "columnName": "visibility",
            "affinity": "INTEGER",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "uid"
          ],
          "autoGenerate": true
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "AccountEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domain",
            "columnName": "domain",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "accessToken",
            "columnName": "accessToken",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "isActive",
            "columnName": "isActive",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "accountId",
            "columnName": "accountId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "username",
            "columnName": "username",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "displayName",
            "columnName": "displayName",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "profilePictureUrl",
            "columnName": "profilePictureUrl",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "notificationsEnabled",
            "columnName": "notificationsEnabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsMentioned",
            "columnName": "notificationsMentioned",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsFollowed",
            "columnName": "notificationsFollowed",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsReblogged",
            "columnName": "notificationsReblogged",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsFavorited",
            "columnName": "notificationsFavorited",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationSound",
            "columnName": "notificationSound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationVibration",
            "columnName": "notificationVibration",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationLight",
            "columnName": "notificationLight",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "defaultPostPrivacy",
            "columnName": "defaultPostPrivacy",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "defaultMediaSensitivity",
            "columnName": "defaultMediaSensitivity",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "alwaysShowSensitiveMedia",
            "columnName": "alwaysShowSensitiveMedia",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "mediaPreviewEnabled",
            "columnName": "mediaPreviewEnabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastNotificationId",
            "columnName": "lastNotificationId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "activeNotifications",
            "columnName": "activeNotifications",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id"
          ],
          "autoGenerate": true
        },
        "indices": [
          {
            "name": "index_AccountEntity_domain_accountId",
            "unique": true,
            "columnNames": [
              "domain",
              "accountId"
            ],
            "createSql": "CREATE UNIQUE INDEX `index_AccountEntity_domain_accountId` ON `${TABLE_NAME}` (`domain`, `accountId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "InstanceEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`instance` TEXT NOT NULL, `emojiList` TEXT, `maximumTootCharacters` INTEGER, PRIMARY KEY(`instance`))",
        "fields": [
          {
            "fieldPath": "instance",
            "columnName": "instance",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojiList",
            "columnName": "emojiList",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "maximumTootCharacters",
            "columnName": "maximumTootCharacters",
            "affinity": "INTEGER",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "instance"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"69e310ef98c0f305934d25e763ee0140\")"
    ]
  }
}

================================================
FILE: app/schemas/com.keylesspalace.tusky.db.AppDatabase/11.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 11,
    "identityHash": "f5e93302cf53d4250e455b701bea102f",
    "entities": [
      {
        "tableName": "TootEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT, `urls` TEXT, `descriptions` TEXT, `contentWarning` TEXT, `inReplyToId` TEXT, `inReplyToText` TEXT, `inReplyToUsername` TEXT, `visibility` INTEGER)",
        "fields": [
          {
            "fieldPath": "uid",
            "columnName": "uid",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "text",
            "columnName": "text",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "urls",
            "columnName": "urls",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "descriptions",
            "columnName": "descriptions",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "contentWarning",
            "columnName": "contentWarning",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToId",
            "columnName": "inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToText",
            "columnName": "inReplyToText",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToUsername",
            "columnName": "inReplyToUsername",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "visibility",
            "columnName": "visibility",
            "affinity": "INTEGER",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "uid"
          ],
          "autoGenerate": true
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "AccountEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domain",
            "columnName": "domain",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "accessToken",
            "columnName": "accessToken",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "isActive",
            "columnName": "isActive",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "accountId",
            "columnName": "accountId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "username",
            "columnName": "username",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "displayName",
            "columnName": "displayName",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "profilePictureUrl",
            "columnName": "profilePictureUrl",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "notificationsEnabled",
            "columnName": "notificationsEnabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsMentioned",
            "columnName": "notificationsMentioned",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsFollowed",
            "columnName": "notificationsFollowed",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsReblogged",
            "columnName": "notificationsReblogged",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsFavorited",
            "columnName": "notificationsFavorited",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationSound",
            "columnName": "notificationSound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationVibration",
            "columnName": "notificationVibration",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationLight",
            "columnName": "notificationLight",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "defaultPostPrivacy",
            "columnName": "defaultPostPrivacy",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "defaultMediaSensitivity",
            "columnName": "defaultMediaSensitivity",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "alwaysShowSensitiveMedia",
            "columnName": "alwaysShowSensitiveMedia",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "mediaPreviewEnabled",
            "columnName": "mediaPreviewEnabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastNotificationId",
            "columnName": "lastNotificationId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "activeNotifications",
            "columnName": "activeNotifications",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id"
          ],
          "autoGenerate": true
        },
        "indices": [
          {
            "name": "index_AccountEntity_domain_accountId",
            "unique": true,
            "columnNames": [
              "domain",
              "accountId"
            ],
            "createSql": "CREATE UNIQUE INDEX `index_AccountEntity_domain_accountId` ON `${TABLE_NAME}` (`domain`, `accountId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "InstanceEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`instance` TEXT NOT NULL, `emojiList` TEXT, `maximumTootCharacters` INTEGER, PRIMARY KEY(`instance`))",
        "fields": [
          {
            "fieldPath": "instance",
            "columnName": "instance",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojiList",
            "columnName": "emojiList",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "maximumTootCharacters",
            "columnName": "maximumTootCharacters",
            "affinity": "INTEGER",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "instance"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "TimelineStatusEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `url` TEXT, `timelineUserId` INTEGER NOT NULL, `authorServerId` TEXT, `instance` TEXT, `inReplyToId` TEXT, `inReplyToAccountId` TEXT, `content` TEXT, `createdAt` INTEGER NOT NULL, `emojis` TEXT, `reblogsCount` INTEGER NOT NULL, `favouritesCount` INTEGER NOT NULL, `reblogged` INTEGER NOT NULL, `favourited` INTEGER NOT NULL, `sensitive` INTEGER NOT NULL, `spoilerText` TEXT, `visibility` INTEGER, `attachments` TEXT, `mentions` TEXT, `application` TEXT, `reblogServerId` TEXT, `reblogAccountId` TEXT, PRIMARY KEY(`serverId`, `timelineUserId`), FOREIGN KEY(`authorServerId`, `timelineUserId`) REFERENCES `TimelineAccountEntity`(`serverId`, `timelineUserId`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
        "fields": [
          {
            "fieldPath": "serverId",
            "columnName": "serverId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "url",
            "columnName": "url",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "timelineUserId",
            "columnName": "timelineUserId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "authorServerId",
            "columnName": "authorServerId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "instance",
            "columnName": "instance",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToId",
            "columnName": "inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToAccountId",
            "columnName": "inReplyToAccountId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "content",
            "columnName": "content",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "createdAt",
            "columnName": "createdAt",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "reblogsCount",
            "columnName": "reblogsCount",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "favouritesCount",
            "columnName": "favouritesCount",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "reblogged",
            "columnName": "reblogged",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "favourited",
            "columnName": "favourited",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "sensitive",
            "columnName": "sensitive",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "spoilerText",
            "columnName": "spoilerText",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "visibility",
            "columnName": "visibility",
            "affinity": "INTEGER",
            "notNull": false
          },
          {
            "fieldPath": "attachments",
            "columnName": "attachments",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "mentions",
            "columnName": "mentions",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "application",
            "columnName": "application",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "reblogServerId",
            "columnName": "reblogServerId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "reblogAccountId",
            "columnName": "reblogAccountId",
            "affinity": "TEXT",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "serverId",
            "timelineUserId"
          ],
          "autoGenerate": false
        },
        "indices": [
          {
            "name": "index_TimelineStatusEntity_authorServerId_timelineUserId",
            "unique": false,
            "columnNames": [
              "authorServerId",
              "timelineUserId"
            ],
            "createSql": "CREATE  INDEX `index_TimelineStatusEntity_authorServerId_timelineUserId` ON `${TABLE_NAME}` (`authorServerId`, `timelineUserId`)"
          }
        ],
        "foreignKeys": [
          {
            "table": "TimelineAccountEntity",
            "onDelete": "NO ACTION",
            "onUpdate": "NO ACTION",
            "columns": [
              "authorServerId",
              "timelineUserId"
            ],
            "referencedColumns": [
              "serverId",
              "timelineUserId"
            ]
          }
        ]
      },
      {
        "tableName": "TimelineAccountEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `timelineUserId` INTEGER NOT NULL, `instance` TEXT NOT NULL, `localUsername` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `url` TEXT NOT NULL, `avatar` TEXT NOT NULL, `emojis` TEXT NOT NULL, PRIMARY KEY(`serverId`, `timelineUserId`))",
        "fields": [
          {
            "fieldPath": "serverId",
            "columnName": "serverId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "timelineUserId",
            "columnName": "timelineUserId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "instance",
            "columnName": "instance",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "localUsername",
            "columnName": "localUsername",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "username",
            "columnName": "username",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "displayName",
            "columnName": "displayName",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "url",
            "columnName": "url",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "avatar",
            "columnName": "avatar",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "serverId",
            "timelineUserId"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"f5e93302cf53d4250e455b701bea102f\")"
    ]
  }
}

================================================
FILE: app/schemas/com.keylesspalace.tusky.db.AppDatabase/12.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 12,
    "identityHash": "d4d3d4c683ab7f681459b9edab92301c",
    "entities": [
      {
        "tableName": "TootEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT, `urls` TEXT, `descriptions` TEXT, `contentWarning` TEXT, `inReplyToId` TEXT, `inReplyToText` TEXT, `inReplyToUsername` TEXT, `visibility` INTEGER)",
        "fields": [
          {
            "fieldPath": "uid",
            "columnName": "uid",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "text",
            "columnName": "text",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "urls",
            "columnName": "urls",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "descriptions",
            "columnName": "descriptions",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "contentWarning",
            "columnName": "contentWarning",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToId",
            "columnName": "inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToText",
            "columnName": "inReplyToText",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToUsername",
            "columnName": "inReplyToUsername",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "visibility",
            "columnName": "visibility",
            "affinity": "INTEGER",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "uid"
          ],
          "autoGenerate": true
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "AccountEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domain",
            "columnName": "domain",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "accessToken",
            "columnName": "accessToken",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "isActive",
            "columnName": "isActive",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "accountId",
            "columnName": "accountId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "username",
            "columnName": "username",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "displayName",
            "columnName": "displayName",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "profilePictureUrl",
            "columnName": "profilePictureUrl",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "notificationsEnabled",
            "columnName": "notificationsEnabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsMentioned",
            "columnName": "notificationsMentioned",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsFollowed",
            "columnName": "notificationsFollowed",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsReblogged",
            "columnName": "notificationsReblogged",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsFavorited",
            "columnName": "notificationsFavorited",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationSound",
            "columnName": "notificationSound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationVibration",
            "columnName": "notificationVibration",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationLight",
            "columnName": "notificationLight",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "defaultPostPrivacy",
            "columnName": "defaultPostPrivacy",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "defaultMediaSensitivity",
            "columnName": "defaultMediaSensitivity",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "alwaysShowSensitiveMedia",
            "columnName": "alwaysShowSensitiveMedia",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "mediaPreviewEnabled",
            "columnName": "mediaPreviewEnabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastNotificationId",
            "columnName": "lastNotificationId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "activeNotifications",
            "columnName": "activeNotifications",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "tabPreferences",
            "columnName": "tabPreferences",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id"
          ],
          "autoGenerate": true
        },
        "indices": [
          {
            "name": "index_AccountEntity_domain_accountId",
            "unique": true,
            "columnNames": [
              "domain",
              "accountId"
            ],
            "createSql": "CREATE UNIQUE INDEX `index_AccountEntity_domain_accountId` ON `${TABLE_NAME}` (`domain`, `accountId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "InstanceEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`instance` TEXT NOT NULL, `emojiList` TEXT, `maximumTootCharacters` INTEGER, PRIMARY KEY(`instance`))",
        "fields": [
          {
            "fieldPath": "instance",
            "columnName": "instance",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojiList",
            "columnName": "emojiList",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "maximumTootCharacters",
            "columnName": "maximumTootCharacters",
            "affinity": "INTEGER",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "instance"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "TimelineStatusEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `url` TEXT, `timelineUserId` INTEGER NOT NULL, `authorServerId` TEXT, `instance` TEXT, `inReplyToId` TEXT, `inReplyToAccountId` TEXT, `content` TEXT, `createdAt` INTEGER NOT NULL, `emojis` TEXT, `reblogsCount` INTEGER NOT NULL, `favouritesCount` INTEGER NOT NULL, `reblogged` INTEGER NOT NULL, `favourited` INTEGER NOT NULL, `sensitive` INTEGER NOT NULL, `spoilerText` TEXT, `visibility` INTEGER, `attachments` TEXT, `mentions` TEXT, `application` TEXT, `reblogServerId` TEXT, `reblogAccountId` TEXT, PRIMARY KEY(`serverId`, `timelineUserId`), FOREIGN KEY(`authorServerId`, `timelineUserId`) REFERENCES `TimelineAccountEntity`(`serverId`, `timelineUserId`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
        "fields": [
          {
            "fieldPath": "serverId",
            "columnName": "serverId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "url",
            "columnName": "url",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "timelineUserId",
            "columnName": "timelineUserId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "authorServerId",
            "columnName": "authorServerId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "instance",
            "columnName": "instance",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToId",
            "columnName": "inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToAccountId",
            "columnName": "inReplyToAccountId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "content",
            "columnName": "content",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "createdAt",
            "columnName": "createdAt",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "reblogsCount",
            "columnName": "reblogsCount",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "favouritesCount",
            "columnName": "favouritesCount",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "reblogged",
            "columnName": "reblogged",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "favourited",
            "columnName": "favourited",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "sensitive",
            "columnName": "sensitive",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "spoilerText",
            "columnName": "spoilerText",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "visibility",
            "columnName": "visibility",
            "affinity": "INTEGER",
            "notNull": false
          },
          {
            "fieldPath": "attachments",
            "columnName": "attachments",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "mentions",
            "columnName": "mentions",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "application",
            "columnName": "application",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "reblogServerId",
            "columnName": "reblogServerId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "reblogAccountId",
            "columnName": "reblogAccountId",
            "affinity": "TEXT",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "serverId",
            "timelineUserId"
          ],
          "autoGenerate": false
        },
        "indices": [
          {
            "name": "index_TimelineStatusEntity_authorServerId_timelineUserId",
            "unique": false,
            "columnNames": [
              "authorServerId",
              "timelineUserId"
            ],
            "createSql": "CREATE  INDEX `index_TimelineStatusEntity_authorServerId_timelineUserId` ON `${TABLE_NAME}` (`authorServerId`, `timelineUserId`)"
          }
        ],
        "foreignKeys": [
          {
            "table": "TimelineAccountEntity",
            "onDelete": "NO ACTION",
            "onUpdate": "NO ACTION",
            "columns": [
              "authorServerId",
              "timelineUserId"
            ],
            "referencedColumns": [
              "serverId",
              "timelineUserId"
            ]
          }
        ]
      },
      {
        "tableName": "TimelineAccountEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `timelineUserId` INTEGER NOT NULL, `instance` TEXT NOT NULL, `localUsername` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `url` TEXT NOT NULL, `avatar` TEXT NOT NULL, `emojis` TEXT NOT NULL, PRIMARY KEY(`serverId`, `timelineUserId`))",
        "fields": [
          {
            "fieldPath": "serverId",
            "columnName": "serverId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "timelineUserId",
            "columnName": "timelineUserId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "instance",
            "columnName": "instance",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "localUsername",
            "columnName": "localUsername",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "username",
            "columnName": "username",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "displayName",
            "columnName": "displayName",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "url",
            "columnName": "url",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "avatar",
            "columnName": "avatar",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "serverId",
            "timelineUserId"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "ConversationEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `id` TEXT NOT NULL, `accounts` TEXT NOT NULL, `unread` INTEGER NOT NULL, `s_id` TEXT NOT NULL, `s_url` TEXT, `s_inReplyToId` TEXT, `s_inReplyToAccountId` TEXT, `s_account` TEXT NOT NULL, `s_content` TEXT NOT NULL, `s_createdAt` INTEGER NOT NULL, `s_emojis` TEXT NOT NULL, `s_favouritesCount` INTEGER NOT NULL, `s_favourited` INTEGER NOT NULL, `s_sensitive` INTEGER NOT NULL, `s_spoilerText` TEXT NOT NULL, `s_attachments` TEXT NOT NULL, `s_mentions` TEXT NOT NULL, `s_showingHiddenContent` INTEGER NOT NULL, `s_expanded` INTEGER NOT NULL, `s_collapsible` INTEGER NOT NULL, `s_collapsed` INTEGER NOT NULL, PRIMARY KEY(`id`, `accountId`))",
        "fields": [
          {
            "fieldPath": "accountId",
            "columnName": "accountId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "accounts",
            "columnName": "accounts",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "unread",
            "columnName": "unread",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.id",
            "columnName": "s_id",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.url",
            "columnName": "s_url",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "lastStatus.inReplyToId",
            "columnName": "s_inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "lastStatus.inReplyToAccountId",
            "columnName": "s_inReplyToAccountId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "lastStatus.account",
            "columnName": "s_account",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.content",
            "columnName": "s_content",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.createdAt",
            "columnName": "s_createdAt",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.emojis",
            "columnName": "s_emojis",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.favouritesCount",
            "columnName": "s_favouritesCount",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.favourited",
            "columnName": "s_favourited",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.sensitive",
            "columnName": "s_sensitive",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.spoilerText",
            "columnName": "s_spoilerText",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.attachments",
            "columnName": "s_attachments",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.mentions",
            "columnName": "s_mentions",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.showingHiddenContent",
            "columnName": "s_showingHiddenContent",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.expanded",
            "columnName": "s_expanded",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.collapsible",
            "columnName": "s_collapsible",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.collapsed",
            "columnName": "s_collapsed",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id",
            "accountId"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"d4d3d4c683ab7f681459b9edab92301c\")"
    ]
  }
}

================================================
FILE: app/schemas/com.keylesspalace.tusky.db.AppDatabase/13.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 13,
    "identityHash": "9a63a3ab2c05004022c350aab0e472c0",
    "entities": [
      {
        "tableName": "TootEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT, `urls` TEXT, `descriptions` TEXT, `contentWarning` TEXT, `inReplyToId` TEXT, `inReplyToText` TEXT, `inReplyToUsername` TEXT, `visibility` INTEGER)",
        "fields": [
          {
            "fieldPath": "uid",
            "columnName": "uid",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "text",
            "columnName": "text",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "urls",
            "columnName": "urls",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "descriptions",
            "columnName": "descriptions",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "contentWarning",
            "columnName": "contentWarning",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToId",
            "columnName": "inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToText",
            "columnName": "inReplyToText",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToUsername",
            "columnName": "inReplyToUsername",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "visibility",
            "columnName": "visibility",
            "affinity": "INTEGER",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "uid"
          ],
          "autoGenerate": true
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "AccountEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domain",
            "columnName": "domain",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "accessToken",
            "columnName": "accessToken",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "isActive",
            "columnName": "isActive",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "accountId",
            "columnName": "accountId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "username",
            "columnName": "username",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "displayName",
            "columnName": "displayName",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "profilePictureUrl",
            "columnName": "profilePictureUrl",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "notificationsEnabled",
            "columnName": "notificationsEnabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsMentioned",
            "columnName": "notificationsMentioned",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsFollowed",
            "columnName": "notificationsFollowed",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsReblogged",
            "columnName": "notificationsReblogged",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationsFavorited",
            "columnName": "notificationsFavorited",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationSound",
            "columnName": "notificationSound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationVibration",
            "columnName": "notificationVibration",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "notificationLight",
            "columnName": "notificationLight",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "defaultPostPrivacy",
            "columnName": "defaultPostPrivacy",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "defaultMediaSensitivity",
            "columnName": "defaultMediaSensitivity",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "alwaysShowSensitiveMedia",
            "columnName": "alwaysShowSensitiveMedia",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "mediaPreviewEnabled",
            "columnName": "mediaPreviewEnabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastNotificationId",
            "columnName": "lastNotificationId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "activeNotifications",
            "columnName": "activeNotifications",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "tabPreferences",
            "columnName": "tabPreferences",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id"
          ],
          "autoGenerate": true
        },
        "indices": [
          {
            "name": "index_AccountEntity_domain_accountId",
            "unique": true,
            "columnNames": [
              "domain",
              "accountId"
            ],
            "createSql": "CREATE UNIQUE INDEX `index_AccountEntity_domain_accountId` ON `${TABLE_NAME}` (`domain`, `accountId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "InstanceEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`instance` TEXT NOT NULL, `emojiList` TEXT, `maximumTootCharacters` INTEGER, PRIMARY KEY(`instance`))",
        "fields": [
          {
            "fieldPath": "instance",
            "columnName": "instance",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojiList",
            "columnName": "emojiList",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "maximumTootCharacters",
            "columnName": "maximumTootCharacters",
            "affinity": "INTEGER",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "instance"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "TimelineStatusEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `url` TEXT, `timelineUserId` INTEGER NOT NULL, `authorServerId` TEXT, `inReplyToId` TEXT, `inReplyToAccountId` TEXT, `content` TEXT, `createdAt` INTEGER NOT NULL, `emojis` TEXT, `reblogsCount` INTEGER NOT NULL, `favouritesCount` INTEGER NOT NULL, `reblogged` INTEGER NOT NULL, `favourited` INTEGER NOT NULL, `sensitive` INTEGER NOT NULL, `spoilerText` TEXT, `visibility` INTEGER, `attachments` TEXT, `mentions` TEXT, `application` TEXT, `reblogServerId` TEXT, `reblogAccountId` TEXT, PRIMARY KEY(`serverId`, `timelineUserId`), FOREIGN KEY(`authorServerId`, `timelineUserId`) REFERENCES `TimelineAccountEntity`(`serverId`, `timelineUserId`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
        "fields": [
          {
            "fieldPath": "serverId",
            "columnName": "serverId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "url",
            "columnName": "url",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "timelineUserId",
            "columnName": "timelineUserId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "authorServerId",
            "columnName": "authorServerId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToId",
            "columnName": "inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToAccountId",
            "columnName": "inReplyToAccountId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "content",
            "columnName": "content",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "createdAt",
            "columnName": "createdAt",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "reblogsCount",
            "columnName": "reblogsCount",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "favouritesCount",
            "columnName": "favouritesCount",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "reblogged",
            "columnName": "reblogged",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "favourited",
            "columnName": "favourited",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "sensitive",
            "columnName": "sensitive",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "spoilerText",
            "columnName": "spoilerText",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "visibility",
            "columnName": "visibility",
            "affinity": "INTEGER",
            "notNull": false
          },
          {
            "fieldPath": "attachments",
            "columnName": "attachments",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "mentions",
            "columnName": "mentions",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "application",
            "columnName": "application",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "reblogServerId",
            "columnName": "reblogServerId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "reblogAccountId",
            "columnName": "reblogAccountId",
            "affinity": "TEXT",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "serverId",
            "timelineUserId"
          ],
          "autoGenerate": false
        },
        "indices": [
          {
            "name": "index_TimelineStatusEntity_authorServerId_timelineUserId",
            "unique": false,
            "columnNames": [
              "authorServerId",
              "timelineUserId"
            ],
            "createSql": "CREATE  INDEX `index_TimelineStatusEntity_authorServerId_timelineUserId` ON `${TABLE_NAME}` (`authorServerId`, `timelineUserId`)"
          }
        ],
        "foreignKeys": [
          {
            "table": "TimelineAccountEntity",
            "onDelete": "NO ACTION",
            "onUpdate": "NO ACTION",
            "columns": [
              "authorServerId",
              "timelineUserId"
            ],
            "referencedColumns": [
              "serverId",
              "timelineUserId"
            ]
          }
        ]
      },
      {
        "tableName": "TimelineAccountEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `timelineUserId` INTEGER NOT NULL, `localUsername` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `url` TEXT NOT NULL, `avatar` TEXT NOT NULL, `emojis` TEXT NOT NULL, PRIMARY KEY(`serverId`, `timelineUserId`))",
        "fields": [
          {
            "fieldPath": "serverId",
            "columnName": "serverId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "timelineUserId",
            "columnName": "timelineUserId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "localUsername",
            "columnName": "localUsername",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "username",
            "columnName": "username",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "displayName",
            "columnName": "displayName",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "url",
            "columnName": "url",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "avatar",
            "columnName": "avatar",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "emojis",
            "columnName": "emojis",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "serverId",
            "timelineUserId"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "ConversationEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `id` TEXT NOT NULL, `accounts` TEXT NOT NULL, `unread` INTEGER NOT NULL, `s_id` TEXT NOT NULL, `s_url` TEXT, `s_inReplyToId` TEXT, `s_inReplyToAccountId` TEXT, `s_account` TEXT NOT NULL, `s_content` TEXT NOT NULL, `s_createdAt` INTEGER NOT NULL, `s_emojis` TEXT NOT NULL, `s_favouritesCount` INTEGER NOT NULL, `s_favourited` INTEGER NOT NULL, `s_sensitive` INTEGER NOT NULL, `s_spoilerText` TEXT NOT NULL, `s_attachments` TEXT NOT NULL, `s_mentions` TEXT NOT NULL, `s_showingHiddenContent` INTEGER NOT NULL, `s_expanded` INTEGER NOT NULL, `s_collapsible` INTEGER NOT NULL, `s_collapsed` INTEGER NOT NULL, PRIMARY KEY(`id`, `accountId`))",
        "fields": [
          {
            "fieldPath": "accountId",
            "columnName": "accountId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "accounts",
            "columnName": "accounts",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "unread",
            "columnName": "unread",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.id",
            "columnName": "s_id",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.url",
            "columnName": "s_url",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "lastStatus.inReplyToId",
            "columnName": "s_inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "lastStatus.inReplyToAccountId",
            "columnName": "s_inReplyToAccountId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "lastStatus.account",
            "columnName": "s_account",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.content",
            "columnName": "s_content",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.createdAt",
            "columnName": "s_createdAt",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.emojis",
            "columnName": "s_emojis",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.favouritesCount",
            "columnName": "s_favouritesCount",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.favourited",
            "columnName": "s_favourited",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.sensitive",
            "columnName": "s_sensitive",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.spoilerText",
            "columnName": "s_spoilerText",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.attachments",
            "columnName": "s_attachments",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.mentions",
            "columnName": "s_mentions",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.showingHiddenContent",
            "columnName": "s_showingHiddenContent",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.expanded",
            "columnName": "s_expanded",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.collapsible",
            "columnName": "s_collapsible",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "lastStatus.collapsed",
            "columnName": "s_collapsed",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id",
            "accountId"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"9a63a3ab2c05004022c350aab0e472c0\")"
    ]
  }
}

================================================
FILE: app/schemas/com.keylesspalace.tusky.db.AppDatabase/14.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 14,
    "identityHash": "b9ca62605345d229ced2bb0c1f2db79b",
    "entities": [
      {
        "tableName": "TootEntity",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT, `urls` TEXT, `descriptions` TEXT, `contentWarning` TEXT, `inReplyToId` TEXT, `inReplyToText` TEXT, `inReplyToUsername` TEXT, `visibility` INTEGER)",
        "fields": [
          {
            "fieldPath": "uid",
            "columnName": "uid",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "text",
            "columnName": "text",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "urls",
            "columnName": "urls",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "descriptions",
            "columnName": "descriptions",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "contentWarning",
            "columnName": "contentWarning",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToId",
            "columnName": "inReplyToId",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToText",
            "columnName": "inReplyToText",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "inReplyToUsername",
            "columnName": "inReplyToUsername",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "visibility",
            "columnName": "visibility",
            "affinity": "INTEGER",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
         
Download .txt
gitextract_7rvtut99/

├── .editorconfig
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1.bug_report.yml
│   │   ├── 2.feature_request.yml
│   │   └── config.yml
│   ├── actions/
│   │   └── setup/
│   │       └── action.yml
│   ├── ci-gradle.properties
│   ├── renovate.json
│   └── workflows/
│       ├── check-and-build.yml
│       ├── deploy-release.yml
│       └── deploy-test.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── app/
│   ├── build.gradle
│   ├── getGitSha.gradle
│   ├── lint-baseline.xml
│   ├── lint.xml
│   ├── proguard-rules.pro
│   ├── schemas/
│   │   └── com.keylesspalace.tusky.db.AppDatabase/
│   │       ├── 10.json
│   │       ├── 11.json
│   │       ├── 12.json
│   │       ├── 13.json
│   │       ├── 14.json
│   │       ├── 15.json
│   │       ├── 16.json
│   │       ├── 17.json
│   │       ├── 18.json
│   │       ├── 19.json
│   │       ├── 20.json
│   │       ├── 21.json
│   │       ├── 22.json
│   │       ├── 23.json
│   │       ├── 24.json
│   │       ├── 25.json
│   │       ├── 26.json
│   │       ├── 27.json
│   │       ├── 28.json
│   │       ├── 29.json
│   │       ├── 30.json
│   │       ├── 31.json
│   │       ├── 32.json
│   │       ├── 33.json
│   │       ├── 34.json
│   │       ├── 35.json
│   │       ├── 36.json
│   │       ├── 37.json
│   │       ├── 38.json
│   │       ├── 39.json
│   │       ├── 40.json
│   │       ├── 41.json
│   │       ├── 42.json
│   │       ├── 43.json
│   │       ├── 44.json
│   │       ├── 45.json
│   │       ├── 46.json
│   │       ├── 47.json
│   │       ├── 48.json
│   │       ├── 49.json
│   │       ├── 50.json
│   │       ├── 51.json
│   │       ├── 52.json
│   │       ├── 53.json
│   │       ├── 54.json
│   │       ├── 56.json
│   │       ├── 58.json
│   │       ├── 60.json
│   │       ├── 62.json
│   │       ├── 64.json
│   │       ├── 66.json
│   │       ├── 68.json
│   │       └── 70.json
│   └── src/
│       ├── green/
│       │   └── res/
│       │       └── values/
│       │           └── flavor-colors.xml
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── keylesspalace/
│       │   │           └── tusky/
│       │   │               ├── AboutActivity.kt
│       │   │               ├── AccountsInListFragment.kt
│       │   │               ├── BaseActivity.kt
│       │   │               ├── BottomSheetActivity.kt
│       │   │               ├── EditProfileActivity.kt
│       │   │               ├── LicenseActivity.kt
│       │   │               ├── ListsActivity.kt
│       │   │               ├── MainActivity.kt
│       │   │               ├── MainViewModel.kt
│       │   │               ├── StatusListActivity.kt
│       │   │               ├── TabData.kt
│       │   │               ├── TabPreferenceActivity.kt
│       │   │               ├── TuskyApplication.kt
│       │   │               ├── ViewMediaActivity.kt
│       │   │               ├── adapter/
│       │   │               │   ├── AccountFieldEditAdapter.kt
│       │   │               │   ├── AccountSelectionAdapter.kt
│       │   │               │   ├── AccountViewHolder.kt
│       │   │               │   ├── EmojiAdapter.kt
│       │   │               │   ├── FilteredStatusViewHolder.kt
│       │   │               │   ├── FollowRequestViewHolder.kt
│       │   │               │   ├── LoadMoreViewHolder.kt
│       │   │               │   ├── LoadStateFooterAdapter.kt
│       │   │               │   ├── LocaleAdapter.kt
│       │   │               │   ├── PlaceholderViewHolder.kt
│       │   │               │   ├── PollAdapter.kt
│       │   │               │   ├── PreviewPollOptionsAdapter.kt
│       │   │               │   ├── StatusBaseViewHolder.java
│       │   │               │   ├── StatusDetailedViewHolder.java
│       │   │               │   ├── StatusViewHolder.java
│       │   │               │   └── TabAdapter.kt
│       │   │               ├── appstore/
│       │   │               │   ├── CacheUpdater.kt
│       │   │               │   ├── Events.kt
│       │   │               │   └── EventsHub.kt
│       │   │               ├── components/
│       │   │               │   ├── account/
│       │   │               │   │   ├── AccountActivity.kt
│       │   │               │   │   ├── AccountFieldAdapter.kt
│       │   │               │   │   ├── AccountPagerAdapter.kt
│       │   │               │   │   ├── AccountViewModel.kt
│       │   │               │   │   ├── list/
│       │   │               │   │   │   ├── ListSelectionFragment.kt
│       │   │               │   │   │   └── ListsForAccountViewModel.kt
│       │   │               │   │   └── media/
│       │   │               │   │       ├── AccountMediaFragment.kt
│       │   │               │   │       ├── AccountMediaGridAdapter.kt
│       │   │               │   │       ├── AccountMediaPagingSource.kt
│       │   │               │   │       ├── AccountMediaRemoteMediator.kt
│       │   │               │   │       ├── AccountMediaViewModel.kt
│       │   │               │   │       ├── GridSpacingItemDecoration.kt
│       │   │               │   │       └── SquareImageView.kt
│       │   │               │   ├── accountlist/
│       │   │               │   │   ├── AccountListActivity.kt
│       │   │               │   │   ├── AccountListFragment.kt
│       │   │               │   │   ├── AccountListPagingSource.kt
│       │   │               │   │   ├── AccountListRemoteMediator.kt
│       │   │               │   │   ├── AccountListViewModel.kt
│       │   │               │   │   ├── AccountViewData.kt
│       │   │               │   │   └── adapter/
│       │   │               │   │       ├── AccountAdapter.kt
│       │   │               │   │       ├── BlocksAdapter.kt
│       │   │               │   │       ├── FollowAdapter.kt
│       │   │               │   │       ├── FollowRequestsAdapter.kt
│       │   │               │   │       ├── FollowRequestsHeaderAdapter.kt
│       │   │               │   │       └── MutesAdapter.kt
│       │   │               │   ├── announcements/
│       │   │               │   │   ├── AnnouncementAdapter.kt
│       │   │               │   │   ├── AnnouncementsActivity.kt
│       │   │               │   │   └── AnnouncementsViewModel.kt
│       │   │               │   ├── compose/
│       │   │               │   │   ├── ComposeActivity.kt
│       │   │               │   │   ├── ComposeAutoCompleteAdapter.kt
│       │   │               │   │   ├── ComposeTokenizer.kt
│       │   │               │   │   ├── ComposeViewModel.kt
│       │   │               │   │   ├── ImageDownsizer.kt
│       │   │               │   │   ├── MediaPreviewAdapter.kt
│       │   │               │   │   ├── MediaUploader.kt
│       │   │               │   │   ├── dialog/
│       │   │               │   │   │   ├── AddPollDialog.kt
│       │   │               │   │   │   ├── AddPollOptionsAdapter.kt
│       │   │               │   │   │   ├── CaptionDialog.kt
│       │   │               │   │   │   └── FocusDialog.kt
│       │   │               │   │   └── view/
│       │   │               │   │       ├── ComposeOptionsView.kt
│       │   │               │   │       ├── ComposeScheduleView.kt
│       │   │               │   │       ├── EditTextTyped.kt
│       │   │               │   │       ├── FocusIndicatorView.kt
│       │   │               │   │       ├── PollPreviewView.kt
│       │   │               │   │       ├── ProgressImageView.kt
│       │   │               │   │       └── TootButton.kt
│       │   │               │   ├── conversation/
│       │   │               │   │   ├── ConversationEntity.kt
│       │   │               │   │   ├── ConversationPagingAdapter.kt
│       │   │               │   │   ├── ConversationViewData.kt
│       │   │               │   │   ├── ConversationViewHolder.java
│       │   │               │   │   ├── ConversationsFragment.kt
│       │   │               │   │   ├── ConversationsRemoteMediator.kt
│       │   │               │   │   └── ConversationsViewModel.kt
│       │   │               │   ├── domainblocks/
│       │   │               │   │   ├── DomainBlocksActivity.kt
│       │   │               │   │   ├── DomainBlocksAdapter.kt
│       │   │               │   │   ├── DomainBlocksFragment.kt
│       │   │               │   │   ├── DomainBlocksPagingSource.kt
│       │   │               │   │   ├── DomainBlocksRemoteMediator.kt
│       │   │               │   │   ├── DomainBlocksRepository.kt
│       │   │               │   │   └── DomainBlocksViewModel.kt
│       │   │               │   ├── drafts/
│       │   │               │   │   ├── DraftHelper.kt
│       │   │               │   │   ├── DraftMediaAdapter.kt
│       │   │               │   │   ├── DraftsActivity.kt
│       │   │               │   │   ├── DraftsAdapter.kt
│       │   │               │   │   └── DraftsViewModel.kt
│       │   │               │   ├── filters/
│       │   │               │   │   ├── EditFilterActivity.kt
│       │   │               │   │   ├── EditFilterViewModel.kt
│       │   │               │   │   ├── FilterExpiration.kt
│       │   │               │   │   ├── FilterExtensions.kt
│       │   │               │   │   ├── FiltersActivity.kt
│       │   │               │   │   ├── FiltersAdapter.kt
│       │   │               │   │   ├── FiltersListener.kt
│       │   │               │   │   └── FiltersViewModel.kt
│       │   │               │   ├── followedtags/
│       │   │               │   │   ├── FollowedTagsActivity.kt
│       │   │               │   │   ├── FollowedTagsAdapter.kt
│       │   │               │   │   ├── FollowedTagsPagingSource.kt
│       │   │               │   │   ├── FollowedTagsRemoteMediator.kt
│       │   │               │   │   └── FollowedTagsViewModel.kt
│       │   │               │   ├── instanceinfo/
│       │   │               │   │   ├── InstanceInfo.kt
│       │   │               │   │   └── InstanceInfoRepository.kt
│       │   │               │   ├── login/
│       │   │               │   │   ├── LoginActivity.kt
│       │   │               │   │   ├── LoginWebViewActivity.kt
│       │   │               │   │   └── LoginWebViewViewModel.kt
│       │   │               │   ├── notifications/
│       │   │               │   │   ├── FollowViewHolder.kt
│       │   │               │   │   ├── ModerationWarningViewHolder.kt
│       │   │               │   │   ├── NotificationPolicySummaryAdapter.kt
│       │   │               │   │   ├── NotificationTypeMappers.kt
│       │   │               │   │   ├── NotificationsFragment.kt
│       │   │               │   │   ├── NotificationsPagingAdapter.kt
│       │   │               │   │   ├── NotificationsRemoteMediator.kt
│       │   │               │   │   ├── NotificationsViewModel.kt
│       │   │               │   │   ├── ReportNotificationViewHolder.kt
│       │   │               │   │   ├── SeveredRelationshipNotificationViewHolder.kt
│       │   │               │   │   ├── StatusNotificationViewHolder.kt
│       │   │               │   │   ├── StatusViewHolder.kt
│       │   │               │   │   ├── UnknownNotificationViewHolder.kt
│       │   │               │   │   └── requests/
│       │   │               │   │       ├── NotificationRequestsActivity.kt
│       │   │               │   │       ├── NotificationRequestsAdapter.kt
│       │   │               │   │       ├── NotificationRequestsPagingSource.kt
│       │   │               │   │       ├── NotificationRequestsRemoteMediator.kt
│       │   │               │   │       ├── NotificationRequestsViewModel.kt
│       │   │               │   │       └── details/
│       │   │               │   │           ├── NotificationRequestDetailsActivity.kt
│       │   │               │   │           ├── NotificationRequestDetailsFragment.kt
│       │   │               │   │           ├── NotificationRequestDetailsPagingSource.kt
│       │   │               │   │           ├── NotificationRequestDetailsRemoteMediator.kt
│       │   │               │   │           └── NotificationRequestDetailsViewModel.kt
│       │   │               │   ├── preference/
│       │   │               │   │   ├── AccountPreferencesFragment.kt
│       │   │               │   │   ├── BasePreferencesFragment.kt
│       │   │               │   │   ├── NotificationPreferencesFragment.kt
│       │   │               │   │   ├── PreferencesActivity.kt
│       │   │               │   │   ├── PreferencesFragment.kt
│       │   │               │   │   ├── ProxyPreferencesFragment.kt
│       │   │               │   │   ├── TabFilterPreferencesFragment.kt
│       │   │               │   │   └── notificationpolicies/
│       │   │               │   │       ├── NotificationPoliciesActivity.kt
│       │   │               │   │       ├── NotificationPoliciesFragment.kt
│       │   │               │   │       ├── NotificationPoliciesViewModel.kt
│       │   │               │   │       └── NotificationPolicyPreference.kt
│       │   │               │   ├── report/
│       │   │               │   │   ├── ReportActivity.kt
│       │   │               │   │   ├── ReportViewModel.kt
│       │   │               │   │   ├── Screen.kt
│       │   │               │   │   ├── adapter/
│       │   │               │   │   │   ├── AdapterHandler.kt
│       │   │               │   │   │   ├── ReportPagerAdapter.kt
│       │   │               │   │   │   ├── StatusViewHolder.kt
│       │   │               │   │   │   ├── StatusesAdapter.kt
│       │   │               │   │   │   └── StatusesPagingSource.kt
│       │   │               │   │   ├── fragments/
│       │   │               │   │   │   ├── ReportDoneFragment.kt
│       │   │               │   │   │   ├── ReportNoteFragment.kt
│       │   │               │   │   │   └── ReportStatusesFragment.kt
│       │   │               │   │   └── model/
│       │   │               │   │       └── StatusViewState.kt
│       │   │               │   ├── scheduled/
│       │   │               │   │   ├── ScheduledStatusActivity.kt
│       │   │               │   │   ├── ScheduledStatusAdapter.kt
│       │   │               │   │   ├── ScheduledStatusPagingSource.kt
│       │   │               │   │   └── ScheduledStatusViewModel.kt
│       │   │               │   ├── search/
│       │   │               │   │   ├── SearchActivity.kt
│       │   │               │   │   ├── SearchType.kt
│       │   │               │   │   ├── SearchViewModel.kt
│       │   │               │   │   ├── adapter/
│       │   │               │   │   │   ├── SearchAccountsAdapter.kt
│       │   │               │   │   │   ├── SearchHashtagsAdapter.kt
│       │   │               │   │   │   ├── SearchPagerAdapter.kt
│       │   │               │   │   │   ├── SearchPagingSource.kt
│       │   │               │   │   │   ├── SearchPagingSourceFactory.kt
│       │   │               │   │   │   └── SearchStatusesAdapter.kt
│       │   │               │   │   └── fragments/
│       │   │               │   │       ├── SearchAccountsFragment.kt
│       │   │               │   │       ├── SearchFragment.kt
│       │   │               │   │       ├── SearchHashtagsFragment.kt
│       │   │               │   │       └── SearchStatusesFragment.kt
│       │   │               │   ├── systemnotifications/
│       │   │               │   │   ├── NotificationChannelData.kt
│       │   │               │   │   ├── NotificationFetcher.kt
│       │   │               │   │   └── NotificationService.kt
│       │   │               │   ├── timeline/
│       │   │               │   │   ├── TimelineFragment.kt
│       │   │               │   │   ├── TimelinePagingAdapter.kt
│       │   │               │   │   ├── TimelineTypeMappers.kt
│       │   │               │   │   ├── util/
│       │   │               │   │   │   └── TimelineUtils.kt
│       │   │               │   │   └── viewmodel/
│       │   │               │   │       ├── CachedTimelineRemoteMediator.kt
│       │   │               │   │       ├── CachedTimelineViewModel.kt
│       │   │               │   │       ├── NetworkTimelinePagingSource.kt
│       │   │               │   │       ├── NetworkTimelineRemoteMediator.kt
│       │   │               │   │       ├── NetworkTimelineViewModel.kt
│       │   │               │   │       └── TimelineViewModel.kt
│       │   │               │   ├── trending/
│       │   │               │   │   ├── TrendingActivity.kt
│       │   │               │   │   ├── TrendingDateViewHolder.kt
│       │   │               │   │   ├── TrendingTagViewHolder.kt
│       │   │               │   │   ├── TrendingTagsAdapter.kt
│       │   │               │   │   ├── TrendingTagsFragment.kt
│       │   │               │   │   └── viewmodel/
│       │   │               │   │       └── TrendingTagsViewModel.kt
│       │   │               │   └── viewthread/
│       │   │               │       ├── ConversationLineItemDecoration.kt
│       │   │               │       ├── ThreadAdapter.kt
│       │   │               │       ├── ViewThreadActivity.kt
│       │   │               │       ├── ViewThreadFragment.kt
│       │   │               │       ├── ViewThreadViewModel.kt
│       │   │               │       └── edits/
│       │   │               │           ├── ViewEditsAdapter.kt
│       │   │               │           ├── ViewEditsFragment.kt
│       │   │               │           └── ViewEditsViewModel.kt
│       │   │               ├── db/
│       │   │               │   ├── AccountManager.kt
│       │   │               │   ├── AppDatabase.java
│       │   │               │   ├── ConversationsDao.kt
│       │   │               │   ├── Converters.kt
│       │   │               │   ├── DatabaseCleaner.kt
│       │   │               │   ├── DraftsAlert.kt
│       │   │               │   ├── dao/
│       │   │               │   │   ├── AccountDao.kt
│       │   │               │   │   ├── DraftDao.kt
│       │   │               │   │   ├── InstanceDao.kt
│       │   │               │   │   ├── NotificationPolicyDao.kt
│       │   │               │   │   ├── NotificationsDao.kt
│       │   │               │   │   ├── TimelineAccountDao.kt
│       │   │               │   │   ├── TimelineDao.kt
│       │   │               │   │   └── TimelineStatusDao.kt
│       │   │               │   └── entity/
│       │   │               │       ├── AccountEntity.kt
│       │   │               │       ├── DraftEntity.kt
│       │   │               │       ├── HomeTimelineEntity.kt
│       │   │               │       ├── InstanceEntity.kt
│       │   │               │       ├── NotificationEntity.kt
│       │   │               │       ├── NotificationPolicyEntity.kt
│       │   │               │       ├── TimelineAccountEntity.kt
│       │   │               │       └── TimelineStatusEntity.kt
│       │   │               ├── di/
│       │   │               │   ├── CoroutineScopeModule.kt
│       │   │               │   ├── NetworkModule.kt
│       │   │               │   ├── NotificationManagerModule.kt
│       │   │               │   ├── PlayerModule.kt
│       │   │               │   ├── PreferencesEntryPoint.kt
│       │   │               │   └── StorageModule.kt
│       │   │               ├── entity/
│       │   │               │   ├── AccessToken.kt
│       │   │               │   ├── Account.kt
│       │   │               │   ├── AccountWarning.kt
│       │   │               │   ├── Announcement.kt
│       │   │               │   ├── AppCredentials.kt
│       │   │               │   ├── Attachment.kt
│       │   │               │   ├── Conversation.kt
│       │   │               │   ├── DeletedStatus.kt
│       │   │               │   ├── Emoji.kt
│       │   │               │   ├── Error.kt
│       │   │               │   ├── Filter.kt
│       │   │               │   ├── FilterKeyword.kt
│       │   │               │   ├── FilterResult.kt
│       │   │               │   ├── FilterV1.kt
│       │   │               │   ├── HashTag.kt
│       │   │               │   ├── Instance.kt
│       │   │               │   ├── InstanceV1.kt
│       │   │               │   ├── Marker.kt
│       │   │               │   ├── MastoList.kt
│       │   │               │   ├── MediaUploadResult.kt
│       │   │               │   ├── NewStatus.kt
│       │   │               │   ├── Notification.kt
│       │   │               │   ├── NotificationPolicy.kt
│       │   │               │   ├── NotificationRequest.kt
│       │   │               │   ├── NotificationSubscribeResult.kt
│       │   │               │   ├── Poll.kt
│       │   │               │   ├── PreviewCard.kt
│       │   │               │   ├── Relationship.kt
│       │   │               │   ├── RelationshipSeveranceEvent.kt
│       │   │               │   ├── Report.kt
│       │   │               │   ├── ScheduledStatus.kt
│       │   │               │   ├── SearchResult.kt
│       │   │               │   ├── Status.kt
│       │   │               │   ├── StatusContext.kt
│       │   │               │   ├── StatusEdit.kt
│       │   │               │   ├── StatusParams.kt
│       │   │               │   ├── StatusSource.kt
│       │   │               │   ├── TimelineAccount.kt
│       │   │               │   ├── Translation.kt
│       │   │               │   └── TrendingTagsResult.kt
│       │   │               ├── fragment/
│       │   │               │   ├── SFragment.kt
│       │   │               │   ├── ViewImageFragment.kt
│       │   │               │   ├── ViewMediaFragment.kt
│       │   │               │   └── ViewVideoFragment.kt
│       │   │               ├── interfaces/
│       │   │               │   ├── AccountActionListener.kt
│       │   │               │   ├── AccountSelectionListener.kt
│       │   │               │   ├── ActionButtonActivity.java
│       │   │               │   ├── HashtagActionListener.kt
│       │   │               │   ├── LinkListener.kt
│       │   │               │   ├── RefreshableFragment.kt
│       │   │               │   ├── ReselectableFragment.kt
│       │   │               │   └── StatusActionListener.kt
│       │   │               ├── json/
│       │   │               │   ├── Guarded.kt
│       │   │               │   ├── GuardedAdapter.kt
│       │   │               │   └── NotificationTypeAdapter.kt
│       │   │               ├── network/
│       │   │               │   ├── ApiFactory.kt
│       │   │               │   ├── FailingCall.kt
│       │   │               │   ├── FilterModel.kt
│       │   │               │   ├── MastodonApi.kt
│       │   │               │   ├── MediaUploadApi.kt
│       │   │               │   └── UriRequestBody.kt
│       │   │               ├── pager/
│       │   │               │   ├── ImagePagerAdapter.kt
│       │   │               │   ├── MainPagerAdapter.kt
│       │   │               │   └── SingleImagePagerAdapter.kt
│       │   │               ├── receiver/
│       │   │               │   ├── NotificationBlockStateBroadcastReceiver.kt
│       │   │               │   ├── SendStatusBroadcastReceiver.kt
│       │   │               │   └── UnifiedPushBroadcastReceiver.kt
│       │   │               ├── service/
│       │   │               │   ├── SendStatusService.kt
│       │   │               │   ├── ServiceClient.kt
│       │   │               │   └── TuskyTileService.kt
│       │   │               ├── settings/
│       │   │               │   ├── AccountPreferenceDataStore.kt
│       │   │               │   ├── DefaultReplyVisibility.kt
│       │   │               │   ├── ProxyConfiguration.kt
│       │   │               │   ├── SettingsConstants.kt
│       │   │               │   └── SettingsDSL.kt
│       │   │               ├── usecase/
│       │   │               │   ├── DeveloperToolsUseCase.kt
│       │   │               │   ├── LogoutUsecase.kt
│       │   │               │   ├── NotificationPolicyUsecase.kt
│       │   │               │   └── TimelineCases.kt
│       │   │               ├── util/
│       │   │               │   ├── AbsoluteTimeFormatter.kt
│       │   │               │   ├── ActivityExtensions.kt
│       │   │               │   ├── AlertDialogExtensions.kt
│       │   │               │   ├── AsciiFolding.kt
│       │   │               │   ├── AttachmentHelper.kt
│       │   │               │   ├── BindingHolder.kt
│       │   │               │   ├── BlurHashDecoder.kt
│       │   │               │   ├── BlurhashDrawable.kt
│       │   │               │   ├── BundleExtensions.kt
│       │   │               │   ├── CardViewMode.kt
│       │   │               │   ├── CompositeWithOpaqueBackground.kt
│       │   │               │   ├── CryptoUtil.kt
│       │   │               │   ├── CustomEmojiHelper.kt
│       │   │               │   ├── CustomFragmentStateAdapter.kt
│       │   │               │   ├── FocalPointUtil.kt
│       │   │               │   ├── GlideExtensions.kt
│       │   │               │   ├── GlideModule.kt
│       │   │               │   ├── HttpHeaderLink.kt
│       │   │               │   ├── IOUtils.kt
│       │   │               │   ├── IconUtils.kt
│       │   │               │   ├── ImageLoadingHelper.kt
│       │   │               │   ├── Lazy.kt
│       │   │               │   ├── LifecycleExtensions.kt
│       │   │               │   ├── LinkHelper.kt
│       │   │               │   ├── ListStatusAccessibilityDelegate.kt
│       │   │               │   ├── ListUtils.kt
│       │   │               │   ├── LocaleExtensions.kt
│       │   │               │   ├── LocaleManager.kt
│       │   │               │   ├── LocaleUtils.kt
│       │   │               │   ├── MediaUtils.kt
│       │   │               │   ├── NoUnderlineURLSpan.kt
│       │   │               │   ├── NumberUtils.kt
│       │   │               │   ├── PickMediaFiles.kt
│       │   │               │   ├── RelativeTimeUpdater.kt
│       │   │               │   ├── Resource.kt
│       │   │               │   ├── RickRoll.kt
│       │   │               │   ├── ShareShortcutHelper.kt
│       │   │               │   ├── SharedPreferencesExtensions.kt
│       │   │               │   ├── SmartLengthInputFilter.kt
│       │   │               │   ├── SpanUtils.kt
│       │   │               │   ├── StatusDisplayOptions.kt
│       │   │               │   ├── StatusParsingHelper.kt
│       │   │               │   ├── StatusViewHelper.kt
│       │   │               │   ├── StringUtils.kt
│       │   │               │   ├── ThemeUtils.kt
│       │   │               │   ├── ThrowableExtensions.kt
│       │   │               │   ├── TimestampUtils.kt
│       │   │               │   ├── TouchDelegateHelper.kt
│       │   │               │   ├── ViewBindingExtensions.kt
│       │   │               │   ├── ViewDataUtils.kt
│       │   │               │   ├── ViewExtensions.kt
│       │   │               │   └── twittertext/
│       │   │               │       ├── Regex.java
│       │   │               │       └── TldLists.java
│       │   │               ├── view/
│       │   │               │   ├── AdaptiveTabLayout.kt
│       │   │               │   ├── BackgroundMessageView.kt
│       │   │               │   ├── BezelImageView.kt
│       │   │               │   ├── ClickableSpanTextView.kt
│       │   │               │   ├── ConfirmationBottomSheet.kt
│       │   │               │   ├── EmojiPicker.kt
│       │   │               │   ├── GraphView.kt
│       │   │               │   ├── HashtagPickerDialog.kt
│       │   │               │   ├── LicenseCard.kt
│       │   │               │   ├── MediaPreviewImageView.kt
│       │   │               │   ├── MediaPreviewLayout.kt
│       │   │               │   ├── MuteAccountDialog.kt
│       │   │               │   ├── SliderPreference.kt
│       │   │               │   └── TuskySwipeRefreshLayout.kt
│       │   │               ├── viewdata/
│       │   │               │   ├── AttachmentViewData.kt
│       │   │               │   ├── NotificationViewData.kt
│       │   │               │   ├── PollViewData.kt
│       │   │               │   ├── StatusViewData.kt
│       │   │               │   └── TrendingViewData.kt
│       │   │               ├── viewmodel/
│       │   │               │   ├── AccountsInListViewModel.kt
│       │   │               │   ├── EditProfileViewModel.kt
│       │   │               │   └── ListsViewModel.kt
│       │   │               └── worker/
│       │   │                   ├── NotificationWorker.kt
│       │   │                   └── PruneCacheWorker.kt
│       │   └── res/
│       │       ├── anim/
│       │       │   ├── activity_close_enter.xml
│       │       │   ├── activity_close_exit.xml
│       │       │   ├── activity_open_enter.xml
│       │       │   ├── activity_open_exit.xml
│       │       │   └── fast_out_extra_slow_in.xml
│       │       ├── color/
│       │       │   ├── account_tab_font_color.xml
│       │       │   ├── color_background_transparent_60.xml
│       │       │   ├── compound_button_color.xml
│       │       │   ├── selectable_chip_background.xml
│       │       │   └── text_input_layout_box_stroke_color.xml
│       │       ├── drawable/
│       │       │   ├── audio_file_preview.xml
│       │       │   ├── avatar_border.xml
│       │       │   ├── avatar_default.xml
│       │       │   ├── background_dialog_activity.xml
│       │       │   ├── badge_background.xml
│       │       │   ├── bot_badge.xml
│       │       │   ├── card_image_placeholder.xml
│       │       │   ├── conversation_thread_line.xml
│       │       │   ├── description_bg_expanded.xml
│       │       │   ├── dialog_background.xml
│       │       │   ├── elephant_friend.xml
│       │       │   ├── elephant_friend_empty.xml
│       │       │   ├── errorphant_error.xml
│       │       │   ├── errorphant_offline.xml
│       │       │   ├── ic_add_24dp.xml
│       │       │   ├── ic_add_a_photo_32dp_filled.xml
│       │       │   ├── ic_arrow_back_24dp.xml
│       │       │   ├── ic_arrow_drop_down_24dp.xml
│       │       │   ├── ic_arrow_drop_up_24dp.xml
│       │       │   ├── ic_attach_file_24dp.xml
│       │       │   ├── ic_block_24dp.xml
│       │       │   ├── ic_bookmark_24dp.xml
│       │       │   ├── ic_bookmark_24dp_filled.xml
│       │       │   ├── ic_bot_24dp.xml
│       │       │   ├── ic_bottom_navigation_24dp.xml
│       │       │   ├── ic_bottom_navigation_24dp_mirrored.xml
│       │       │   ├── ic_campaign_24dp.xml
│       │       │   ├── ic_cancel_24dp_filled.xml
│       │       │   ├── ic_check_24dp.xml
│       │       │   ├── ic_check_box_outline_blank_18dp.xml
│       │       │   ├── ic_check_circle_24dp.xml
│       │       │   ├── ic_chevron_right_24dp.xml
│       │       │   ├── ic_close_24dp.xml
│       │       │   ├── ic_comments_disabled_24dp.xml
│       │       │   ├── ic_content_copy_24dp.xml
│       │       │   ├── ic_developer_mode_24dp.xml
│       │       │   ├── ic_done_outline_24dp.xml
│       │       │   ├── ic_download_24dp.xml
│       │       │   ├── ic_drag_indicator_24dp.xml
│       │       │   ├── ic_edit_24dp_filled.xml
│       │       │   ├── ic_edit_document_24dp.xml
│       │       │   ├── ic_email_alternate_18dp.xml
│       │       │   ├── ic_email_alternate_24dp.xml
│       │       │   ├── ic_error_24dp.xml
│       │       │   ├── ic_feedback_24dp_filled.xml
│       │       │   ├── ic_filter_alt_24dp.xml
│       │       │   ├── ic_flag_24dp.xml
│       │       │   ├── ic_format_size_24dp.xml
│       │       │   ├── ic_gavel_24dp.xml
│       │       │   ├── ic_gif_box_24dp.xml
│       │       │   ├── ic_group_24dp.xml
│       │       │   ├── ic_group_24dp_filled.xml
│       │       │   ├── ic_heart_broken_24.xml
│       │       │   ├── ic_help_24dp.xml
│       │       │   ├── ic_home_24dp.xml
│       │       │   ├── ic_home_24dp_filled.xml
│       │       │   ├── ic_image_24dp.xml
│       │       │   ├── ic_info_24dp.xml
│       │       │   ├── ic_insert_chart_24dp.xml
│       │       │   ├── ic_insert_chart_24dp_filled.xml
│       │       │   ├── ic_list_alt_24dp.xml
│       │       │   ├── ic_list_alt_24dp_filled.xml
│       │       │   ├── ic_local_fire_department_24dp.xml
│       │       │   ├── ic_local_fire_department_24dp_filled.xml
│       │       │   ├── ic_lock_24dp.xml
│       │       │   ├── ic_lock_24dp_filled.xml
│       │       │   ├── ic_lock_open_24dp.xml
│       │       │   ├── ic_logout_24dp.xml
│       │       │   ├── ic_mail_24dp.xml
│       │       │   ├── ic_mail_24dp_filled.xml
│       │       │   ├── ic_manage_accounts_24dp.xml
│       │       │   ├── ic_mood_24dp.xml
│       │       │   ├── ic_more_horiz_24dp.xml
│       │       │   ├── ic_more_vert_24dp.xml
│       │       │   ├── ic_music_box_24dp.xml
│       │       │   ├── ic_notifications_24dp.xml
│       │       │   ├── ic_notifications_24dp_filled.xml
│       │       │   ├── ic_notifications_active_24dp.xml
│       │       │   ├── ic_open_in_new_24dp.xml
│       │       │   ├── ic_palette_24dp.xml
│       │       │   ├── ic_person_24dp.xml
│       │       │   ├── ic_person_add_24dp_mirrored.xml
│       │       │   ├── ic_person_add_24dp_mirrored_filled.xml
│       │       │   ├── ic_person_remove_24dp_mirrored.xml
│       │       │   ├── ic_photo_camera_24dp.xml
│       │       │   ├── ic_public_24dp.xml
│       │       │   ├── ic_radio_button_unchecked_18dp.xml
│       │       │   ├── ic_reblog_direct_24dp.xml
│       │       │   ├── ic_repeat_18dp.xml
│       │       │   ├── ic_repeat_24dp.xml
│       │       │   ├── ic_repeat_active_24dp.xml
│       │       │   ├── ic_reply_18dp.xml
│       │       │   ├── ic_reply_24dp.xml
│       │       │   ├── ic_reply_all_24dp.xml
│       │       │   ├── ic_schedule_24dp.xml
│       │       │   ├── ic_search_24dp.xml
│       │       │   ├── ic_send_24dp.xml
│       │       │   ├── ic_settings_24dp.xml
│       │       │   ├── ic_share_24dp.xml
│       │       │   ├── ic_slideshow_24dp.xml
│       │       │   ├── ic_sort_24dp.xml
│       │       │   ├── ic_spellcheck_24dp.xml
│       │       │   ├── ic_star_24dp.xml
│       │       │   ├── ic_star_24dp_filled.xml
│       │       │   ├── ic_tabs_24dp.xml
│       │       │   ├── ic_tag_24dp.xml
│       │       │   ├── ic_translate_24dp.xml
│       │       │   ├── ic_trip_24dp.xml
│       │       │   ├── ic_verified_18dp.xml
│       │       │   ├── ic_visibility_24dp.xml
│       │       │   ├── ic_visibility_off_24dp.xml
│       │       │   ├── ic_volume_off_24dp.xml
│       │       │   ├── ic_volume_up_24dp.xml
│       │       │   ├── ic_whatshot_24dp.xml
│       │       │   ├── ic_whatshot_24dp_filled.xml
│       │       │   ├── ic_zoom_in_24dp.xml
│       │       │   ├── ic_zoom_out_24dp.xml
│       │       │   ├── launcher_foreground.xml
│       │       │   ├── launcher_monochrome.xml
│       │       │   ├── materialdrawer_shape_large.xml
│       │       │   ├── materialdrawer_shape_small.xml
│       │       │   ├── media_preview_outline.xml
│       │       │   ├── media_warning_bg.xml
│       │       │   ├── play_indicator.xml
│       │       │   ├── poll_option_background.xml
│       │       │   ├── poll_option_shape.xml
│       │       │   ├── report_success_background.xml
│       │       │   ├── round_button.xml
│       │       │   ├── splashscreen.xml
│       │       │   ├── status_divider.xml
│       │       │   ├── tab_icon_bookmarks.xml
│       │       │   ├── tab_icon_direct.xml
│       │       │   ├── tab_icon_home.xml
│       │       │   ├── tab_icon_list.xml
│       │       │   ├── tab_icon_local.xml
│       │       │   ├── tab_icon_notifications.xml
│       │       │   ├── tab_icon_trending_posts.xml
│       │       │   ├── tab_icon_trending_tags.xml
│       │       │   ├── tab_indicator_bottom.xml
│       │       │   ├── tab_indicator_top.xml
│       │       │   ├── text_placeholder.xml
│       │       │   ├── toolbar_icon_arrow_back_with_background.xml
│       │       │   ├── toolbar_icon_more_with_background.xml
│       │       │   ├── tusky_notification_icon.xml
│       │       │   └── tusky_quicksettings_icon.xml
│       │       ├── layout/
│       │       │   ├── activity_about.xml
│       │       │   ├── activity_account.xml
│       │       │   ├── activity_account_list.xml
│       │       │   ├── activity_announcements.xml
│       │       │   ├── activity_compose.xml
│       │       │   ├── activity_drafts.xml
│       │       │   ├── activity_edit_filter.xml
│       │       │   ├── activity_edit_profile.xml
│       │       │   ├── activity_filters.xml
│       │       │   ├── activity_followed_tags.xml
│       │       │   ├── activity_license.xml
│       │       │   ├── activity_lists.xml
│       │       │   ├── activity_login.xml
│       │       │   ├── activity_login_webview.xml
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_notification_policy.xml
│       │       │   ├── activity_notification_request_details.xml
│       │       │   ├── activity_notification_requests.xml
│       │       │   ├── activity_preferences.xml
│       │       │   ├── activity_report.xml
│       │       │   ├── activity_scheduled_status.xml
│       │       │   ├── activity_search.xml
│       │       │   ├── activity_statuslist.xml
│       │       │   ├── activity_tab_preference.xml
│       │       │   ├── activity_trending.xml
│       │       │   ├── activity_view_media.xml
│       │       │   ├── activity_view_thread.xml
│       │       │   ├── bottomsheet_confirmation.xml
│       │       │   ├── card_license.xml
│       │       │   ├── dialog_add_poll.xml
│       │       │   ├── dialog_filter.xml
│       │       │   ├── dialog_focus.xml
│       │       │   ├── dialog_image_description.xml
│       │       │   ├── dialog_list.xml
│       │       │   ├── dialog_mute_account.xml
│       │       │   ├── dialog_pick_hashtag.xml
│       │       │   ├── exo_player_control_view.xml
│       │       │   ├── fragment_account_list.xml
│       │       │   ├── fragment_accounts_in_list.xml
│       │       │   ├── fragment_domain_blocks.xml
│       │       │   ├── fragment_lists_list.xml
│       │       │   ├── fragment_notification_request_details.xml
│       │       │   ├── fragment_report_done.xml
│       │       │   ├── fragment_report_note.xml
│       │       │   ├── fragment_report_statuses.xml
│       │       │   ├── fragment_search.xml
│       │       │   ├── fragment_timeline.xml
│       │       │   ├── fragment_timeline_notifications.xml
│       │       │   ├── fragment_trending_tags.xml
│       │       │   ├── fragment_view_edits.xml
│       │       │   ├── fragment_view_image.xml
│       │       │   ├── fragment_view_thread.xml
│       │       │   ├── fragment_view_video.xml
│       │       │   ├── item_account.xml
│       │       │   ├── item_account_field.xml
│       │       │   ├── item_account_media.xml
│       │       │   ├── item_add_poll_option.xml
│       │       │   ├── item_announcement.xml
│       │       │   ├── item_autocomplete_account.xml
│       │       │   ├── item_autocomplete_emoji.xml
│       │       │   ├── item_autocomplete_hashtag.xml
│       │       │   ├── item_blocked_domain.xml
│       │       │   ├── item_blocked_user.xml
│       │       │   ├── item_conversation.xml
│       │       │   ├── item_draft.xml
│       │       │   ├── item_edit_field.xml
│       │       │   ├── item_emoji_button.xml
│       │       │   ├── item_filtered_notifications_info.xml
│       │       │   ├── item_follow.xml
│       │       │   ├── item_follow_request.xml
│       │       │   ├── item_follow_requests_header.xml
│       │       │   ├── item_followed_hashtag.xml
│       │       │   ├── item_hashtag.xml
│       │       │   ├── item_image_preview_overlay.xml
│       │       │   ├── item_list.xml
│       │       │   ├── item_load_more.xml
│       │       │   ├── item_media_preview.xml
│       │       │   ├── item_moderation_warning_notification.xml
│       │       │   ├── item_muted_user.xml
│       │       │   ├── item_network_state.xml
│       │       │   ├── item_notification_request.xml
│       │       │   ├── item_notifications_load_state_footer_view.xml
│       │       │   ├── item_placeholder.xml
│       │       │   ├── item_poll.xml
│       │       │   ├── item_poll_preview_option.xml
│       │       │   ├── item_preview_card.xml
│       │       │   ├── item_reblog_option.xml
│       │       │   ├── item_removable.xml
│       │       │   ├── item_report_notification.xml
│       │       │   ├── item_report_status.xml
│       │       │   ├── item_scheduled_status.xml
│       │       │   ├── item_severed_relationship_notification.xml
│       │       │   ├── item_status.xml
│       │       │   ├── item_status_bottom_sheet.xml
│       │       │   ├── item_status_detailed.xml
│       │       │   ├── item_status_edit.xml
│       │       │   ├── item_status_filtered.xml
│       │       │   ├── item_status_notification.xml
│       │       │   ├── item_tab_preference.xml
│       │       │   ├── item_tab_preference_small.xml
│       │       │   ├── item_trending_cell.xml
│       │       │   ├── item_trending_date.xml
│       │       │   ├── item_unknown_notification.xml
│       │       │   ├── material_drawer_header.xml
│       │       │   ├── notifications_filter.xml
│       │       │   ├── pref_slider.xml
│       │       │   ├── preference_material_switch.xml
│       │       │   ├── preference_notification_policy.xml
│       │       │   ├── search_view.xml
│       │       │   ├── simple_list_item_1.xml
│       │       │   ├── toolbar_basic.xml
│       │       │   ├── view_background_message.xml
│       │       │   ├── view_compose_options.xml
│       │       │   ├── view_compose_schedule.xml
│       │       │   └── view_poll_preview.xml
│       │       ├── layout-land/
│       │       │   ├── fragment_report_done.xml
│       │       │   └── item_trending_cell.xml
│       │       ├── layout-sw640dp/
│       │       │   ├── fragment_timeline.xml
│       │       │   ├── fragment_timeline_notifications.xml
│       │       │   └── fragment_view_thread.xml
│       │       ├── menu/
│       │       │   ├── account_toolbar.xml
│       │       │   ├── activity_announcements.xml
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_notification_requests.xml
│       │       │   ├── activity_scheduled_status.xml
│       │       │   ├── conversation_more.xml
│       │       │   ├── edit_profile_toolbar.xml
│       │       │   ├── fragment_account_media.xml
│       │       │   ├── fragment_conversations.xml
│       │       │   ├── fragment_notifications.xml
│       │       │   ├── fragment_report_statuses.xml
│       │       │   ├── fragment_search.xml
│       │       │   ├── fragment_timeline.xml
│       │       │   ├── fragment_view_edits.xml
│       │       │   ├── fragment_view_thread.xml
│       │       │   ├── list_actions.xml
│       │       │   ├── search_toolbar.xml
│       │       │   ├── status_more.xml
│       │       │   ├── status_more_for_user.xml
│       │       │   ├── view_hashtag_toolbar.xml
│       │       │   └── view_media_toolbar.xml
│       │       ├── mipmap-anydpi-v26/
│       │       │   └── ic_launcher.xml
│       │       ├── raw/
│       │       │   ├── apache.txt
│       │       │   ├── isrg_root_x1.pem
│       │       │   └── isrg_root_x2.pem
│       │       ├── values/
│       │       │   ├── actions.xml
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── dimens.xml
│       │       │   ├── donottranslate.xml
│       │       │   ├── ids.xml
│       │       │   ├── string-arrays.xml
│       │       │   ├── strings.xml
│       │       │   ├── styles.xml
│       │       │   ├── theme_colors.xml
│       │       │   ├── toot_button.xml
│       │       │   └── values.xml
│       │       ├── values-ar/
│       │       │   └── strings.xml
│       │       ├── values-be/
│       │       │   └── strings.xml
│       │       ├── values-ber/
│       │       │   └── strings.xml
│       │       ├── values-bg/
│       │       │   └── strings.xml
│       │       ├── values-bn-rBD/
│       │       │   └── strings.xml
│       │       ├── values-bn-rIN/
│       │       │   └── strings.xml
│       │       ├── values-ca/
│       │       │   └── strings.xml
│       │       ├── values-ckb/
│       │       │   └── strings.xml
│       │       ├── values-cs/
│       │       │   └── strings.xml
│       │       ├── values-cy/
│       │       │   └── strings.xml
│       │       ├── values-de/
│       │       │   └── strings.xml
│       │       ├── values-el/
│       │       │   └── strings.xml
│       │       ├── values-en-rAU/
│       │       │   └── strings.xml
│       │       ├── values-en-rGB/
│       │       │   └── strings.xml
│       │       ├── values-eo/
│       │       │   └── strings.xml
│       │       ├── values-es/
│       │       │   └── strings.xml
│       │       ├── values-eu/
│       │       │   └── strings.xml
│       │       ├── values-fa/
│       │       │   └── strings.xml
│       │       ├── values-fi/
│       │       │   └── strings.xml
│       │       ├── values-fr/
│       │       │   └── strings.xml
│       │       ├── values-fr-rBE/
│       │       │   └── strings.xml
│       │       ├── values-fy/
│       │       │   └── strings.xml
│       │       ├── values-ga/
│       │       │   └── strings.xml
│       │       ├── values-gd/
│       │       │   └── strings.xml
│       │       ├── values-gl/
│       │       │   └── strings.xml
│       │       ├── values-hi/
│       │       │   └── strings.xml
│       │       ├── values-hu/
│       │       │   └── strings.xml
│       │       ├── values-in/
│       │       │   └── strings.xml
│       │       ├── values-is/
│       │       │   └── strings.xml
│       │       ├── values-it/
│       │       │   └── strings.xml
│       │       ├── values-iw/
│       │       │   └── strings.xml
│       │       ├── values-ja/
│       │       │   └── strings.xml
│       │       ├── values-kab/
│       │       │   └── strings.xml
│       │       ├── values-ko/
│       │       │   └── strings.xml
│       │       ├── values-large/
│       │       │   ├── dimens.xml
│       │       │   └── styles.xml
│       │       ├── values-large-land/
│       │       │   └── dimens.xml
│       │       ├── values-lb/
│       │       │   └── strings.xml
│       │       ├── values-lv/
│       │       │   └── strings.xml
│       │       ├── values-ml/
│       │       │   └── strings.xml
│       │       ├── values-nb-rNO/
│       │       │   └── strings.xml
│       │       ├── values-night/
│       │       │   └── theme_colors.xml
│       │       ├── values-nl/
│       │       │   └── strings.xml
│       │       ├── values-oc/
│       │       │   └── strings.xml
│       │       ├── values-or/
│       │       │   └── strings.xml
│       │       ├── values-pa/
│       │       │   └── strings.xml
│       │       ├── values-pl/
│       │       │   └── strings.xml
│       │       ├── values-pt-rBR/
│       │       │   └── strings.xml
│       │       ├── values-pt-rPT/
│       │       │   └── strings.xml
│       │       ├── values-ru/
│       │       │   └── strings.xml
│       │       ├── values-sa/
│       │       │   └── strings.xml
│       │       ├── values-si/
│       │       │   └── strings.xml
│       │       ├── values-sk/
│       │       │   └── strings.xml
│       │       ├── values-sl/
│       │       │   └── strings.xml
│       │       ├── values-small/
│       │       │   └── integer.xml
│       │       ├── values-sv/
│       │       │   └── strings.xml
│       │       ├── values-sw380dp/
│       │       │   └── toot_button.xml
│       │       ├── values-ta/
│       │       │   └── strings.xml
│       │       ├── values-te/
│       │       │   └── strings.xml
│       │       ├── values-th/
│       │       │   └── strings.xml
│       │       ├── values-tr/
│       │       │   └── strings.xml
│       │       ├── values-uk/
│       │       │   └── strings.xml
│       │       ├── values-v27/
│       │       │   └── styles.xml
│       │       ├── values-v35/
│       │       │   └── values.xml
│       │       ├── values-vi/
│       │       │   └── strings.xml
│       │       ├── values-w640dp/
│       │       │   ├── dimens.xml
│       │       │   └── integers.xml
│       │       ├── values-zh-rCN/
│       │       │   └── strings.xml
│       │       ├── values-zh-rHK/
│       │       │   └── strings.xml
│       │       ├── values-zh-rMO/
│       │       │   └── strings.xml
│       │       ├── values-zh-rSG/
│       │       │   └── strings.xml
│       │       ├── values-zh-rTW/
│       │       │   └── strings.xml
│       │       └── xml/
│       │           ├── file_paths.xml
│       │           ├── locales_config.xml
│       │           ├── network_security_config.xml
│       │           ├── searchable.xml
│       │           └── share_shortcuts.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── keylesspalace/
│                       └── tusky/
│                           ├── BottomSheetActivityTest.kt
│                           ├── FilterV1Test.kt
│                           ├── FocalPointUtilTest.kt
│                           ├── MainActivityTest.kt
│                           ├── SpanUtilsTest.kt
│                           ├── StatusComparisonTest.kt
│                           ├── StringUtilsTest.kt
│                           ├── TuskyApplication.kt
│                           ├── components/
│                           │   ├── compose/
│                           │   │   ├── ComposeActivityTest.kt
│                           │   │   ├── ComposeTokenizerTest.kt
│                           │   │   ├── ComposeViewModelTest.kt
│                           │   │   └── StatusLengthTest.kt
│                           │   ├── notifications/
│                           │   │   ├── NotificationFaker.kt
│                           │   │   └── NotificationsRemoteMediatorTest.kt
│                           │   ├── timeline/
│                           │   │   ├── CachedTimelineRemoteMediatorTest.kt
│                           │   │   ├── NetworkTimelinePagingSourceTest.kt
│                           │   │   ├── NetworkTimelineRemoteMediatorTest.kt
│                           │   │   └── TimelineFaker.kt
│                           │   └── viewthread/
│                           │       └── ViewThreadViewModelTest.kt
│                           ├── db/
│                           │   ├── MigrationsTest.kt
│                           │   └── dao/
│                           │       ├── DatabaseCleanerTest.kt
│                           │       ├── NotificationsDaoTest.kt
│                           │       └── TimelineDaoTest.kt
│                           ├── entity/
│                           │   └── ProxyConfigurationTest.kt
│                           ├── json/
│                           │   └── GuardedAdapterTest.kt
│                           ├── network/
│                           │   └── ApiFactoryTest.kt
│                           ├── usecase/
│                           │   └── TimelineCasesTest.kt
│                           └── util/
│                               ├── AbsoluteTimeFormatterTest.kt
│                               ├── HttpHeaderLinkTest.kt
│                               ├── LinkHelperTest.kt
│                               ├── LocaleUtilsTest.kt
│                               ├── NumberUtilsTest.kt
│                               ├── RickRollTest.kt
│                               ├── SmartLengthInputFilterTest.kt
│                               └── TimestampUtilsTest.kt
├── assets/
│   └── tusky_banner.xcf
├── build.gradle
├── doc/
│   ├── PaymentPolicy.md
│   └── Release.md
├── fastlane/
│   └── metadata/
│       └── android/
│           ├── ar/
│           │   ├── changelogs/
│           │   │   ├── 61.txt
│           │   │   ├── 68.txt
│           │   │   └── 70.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── be/
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── bg/
│           │   ├── changelogs/
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 74.txt
│           │   │   └── 77.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── bn-BD/
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── bn-IN/
│           │   ├── changelogs/
│           │   │   └── 67.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ca/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ckb/
│           │   ├── changelogs/
│           │   │   └── 77.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── cs/
│           │   ├── changelogs/
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── cy/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── de/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── el/
│           │   ├── changelogs/
│           │   │   └── 100.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── en-US/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── eo/
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── es/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── eu/
│           │   ├── changelogs/
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── fa/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── fi/
│           │   └── title.txt
│           ├── fr/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ga/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── gd/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── gl/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── hi/
│           │   ├── changelogs/
│           │   │   └── 68.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── hu/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── id/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── is/
│           │   ├── changelogs/
│           │   │   ├── 127.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   └── 89.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── it/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 74.txt
│           │   │   └── 77.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ja/
│           │   ├── changelogs/
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   └── 74.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── kab/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ko/
│           │   ├── changelogs/
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   └── 67.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── lv/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── nb-NO/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── nl/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   └── 94.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── pl/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── pt-BR/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── pt-PT/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 117.txt
│           │   │   ├── 131.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   └── 91.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ru/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── sa/
│           │   ├── changelogs/
│           │   │   ├── 72.txt
│           │   │   └── 74.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── si/
│           │   └── title.txt
│           ├── sk/
│           │   ├── changelogs/
│           │   │   ├── 67.txt
│           │   │   └── 68.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── sl/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   └── 104.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── sv/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── ta/
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── th/
│           │   ├── changelogs/
│           │   │   └── 72.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── tr/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── uk/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── vi/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 103.txt
│           │   │   ├── 104.txt
│           │   │   ├── 105.txt
│           │   │   ├── 106.txt
│           │   │   ├── 107.txt
│           │   │   ├── 108.txt
│           │   │   ├── 109.txt
│           │   │   ├── 110.txt
│           │   │   ├── 111.txt
│           │   │   ├── 112.txt
│           │   │   ├── 113.txt
│           │   │   ├── 115.txt
│           │   │   ├── 117.txt
│           │   │   ├── 119.txt
│           │   │   ├── 123.txt
│           │   │   ├── 124.txt
│           │   │   ├── 127.txt
│           │   │   ├── 131.txt
│           │   │   ├── 133.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           ├── zh-Hans/
│           │   ├── changelogs/
│           │   │   ├── 100.txt
│           │   │   ├── 58.txt
│           │   │   ├── 61.txt
│           │   │   ├── 67.txt
│           │   │   ├── 68.txt
│           │   │   ├── 70.txt
│           │   │   ├── 72.txt
│           │   │   ├── 74.txt
│           │   │   ├── 77.txt
│           │   │   ├── 80.txt
│           │   │   ├── 82.txt
│           │   │   ├── 83.txt
│           │   │   ├── 87.txt
│           │   │   ├── 89.txt
│           │   │   ├── 91.txt
│           │   │   ├── 94.txt
│           │   │   └── 97.txt
│           │   ├── full_description.txt
│           │   ├── short_description.txt
│           │   └── title.txt
│           └── zh-Hant/
│               ├── full_description.txt
│               ├── short_description.txt
│               └── title.txt
├── gradle/
│   ├── libs.versions.toml
│   ├── verification-metadata.xml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
Download .txt
SYMBOL INDEX (142 symbols across 8 files)

FILE: app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java
  class StatusBaseViewHolder (line 88) | public abstract class StatusBaseViewHolder extends RecyclerView.ViewHold...
    class Key (line 89) | public static class Key {
    method StatusBaseViewHolder (line 147) | protected StatusBaseViewHolder(@NonNull View itemView) {
    method setDisplayName (line 217) | protected void setDisplayName(@NonNull String name, @NonNull List<Emoj...
    method setUsername (line 224) | protected void setUsername(@Nullable String name) {
    method toggleContentWarning (line 230) | public void toggleContentWarning() {
    method setSpoilerAndContent (line 234) | protected void setSpoilerAndContent(@NonNull StatusViewData.Concrete s...
    method setContentWarningButtonText (line 267) | private void setContentWarningButtonText(boolean expanded) {
    method toggleExpandedState (line 275) | protected void toggleExpandedState(boolean sensitive,
    method setTextVisible (line 293) | private void setTextVisible(boolean sensitive,
    method hidePoll (line 334) | private void hidePoll() {
    method setAvatar (line 341) | private void setAvatar(String url,
    method setMetaData (line 382) | protected void setMetaData(@NonNull StatusViewData.Concrete statusView...
    method getCreatedAtDescription (line 407) | private CharSequence getCreatedAtDescription(Date createdAt,
    method setReplyButtonImage (line 427) | protected void setReplyButtonImage(boolean isReply) {
    method setReplyCount (line 435) | protected void setReplyCount(int repliesCount, boolean fullStats) {
    method setReblogged (line 449) | private void setReblogged(boolean reblogged) {
    method setRebloggingEnabled (line 454) | private void setRebloggingEnabled(boolean enabled, Status.Visibility v...
    method setFavourited (line 481) | protected void setFavourited(boolean favourited) {
    method setBookmarked (line 485) | protected void setBookmarked(boolean bookmarked) {
    method decodeBlurHash (line 489) | private BitmapDrawable decodeBlurHash(String blurhash) {
    method loadImage (line 493) | private void loadImage(MediaPreviewImageView imageView,
    method setMediaPreviews (line 531) | protected void setMediaPreviews(
    method getLabelIcon (line 607) | @DrawableRes
    method updateMediaLabel (line 618) | private void updateMediaLabel(int index, boolean sensitive, boolean sh...
    method setMediaLabel (line 626) | protected void setMediaLabel(@NonNull List<Attachment> attachments, bo...
    method setAttachmentClickListener (line 648) | private void setAttachmentClickListener(@NonNull View view, @NonNull S...
    method hideSensitiveMediaWarning (line 663) | protected void hideSensitiveMediaWarning() {
    method setupButtons (line 668) | protected void setupButtons(final @NonNull StatusActionListener listener,
    method setupWithStatus (line 732) | public void setupWithStatus(@NonNull StatusViewData.Concrete status,
    method setTranslationStatus (line 807) | private void setTranslationStatus(StatusViewData.Concrete status, Stat...
    method hasPreviewableAttachment (line 830) | protected static boolean hasPreviewableAttachment(@NonNull List<Attach...
    method setDescriptionForStatus (line 839) | private void setDescriptionForStatus(@NonNull StatusViewData.Concrete ...
    method getTranslatedDescription (line 881) | private String getTranslatedDescription(Context context, TranslationVi...
    method getReblogDescription (line 893) | private static CharSequence getReblogDescription(Context context,
    method getMediaDescription (line 905) | private static CharSequence getMediaDescription(Context context,
    method getContentWarningDescription (line 926) | private static CharSequence getContentWarningDescription(Context context,
    method getVisibilityDescription (line 935) | @NonNull
    method getPollDescription (line 962) | private CharSequence getPollDescription(@NonNull StatusViewData.Concre...
    method getFavsText (line 985) | @NonNull
    method getReblogsText (line 990) | @NonNull
    method getMetaDataText (line 995) | private CharSequence getMetaDataText(@NonNull Context context, @Plural...
    method setupPoll (line 1004) | private void setupPoll(PollViewData poll, List<Emoji> emojis,
    method getPollInfoText (line 1078) | private CharSequence getPollInfoText(long timestamp, PollViewData poll,
    method setupCard (line 1105) | protected void setupCard(
    method showStatusContent (line 1267) | public void showStatusContent(boolean show) {

FILE: app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java
  class StatusDetailedViewHolder (line 32) | public class StatusDetailedViewHolder extends StatusBaseViewHolder {
    method StatusDetailedViewHolder (line 39) | public StatusDetailedViewHolder(@NonNull View view) {
    method setMetaData (line 46) | @Override
    method setReblogAndFavCount (line 122) | private void setReblogAndFavCount(int reblogCount, int favCount, Statu...
    method setupWithStatus (line 140) | @Override
    method getVisibilityIcon (line 165) | private @Nullable Drawable getVisibilityIcon(@Nullable Status.Visibili...
    method hideQuantitativeStats (line 208) | private void hideQuantitativeStats() {

FILE: app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java
  class StatusViewHolder (line 43) | public class StatusViewHolder extends StatusBaseViewHolder {
    method StatusViewHolder (line 52) | public StatusViewHolder(@NonNull View itemView) {
    method setupWithStatus (line 60) | @Override
    method setStatusInfoContent (line 105) | private void setStatusInfoContent(final TimelineAccount account,
    method setReblogsCount (line 137) | protected void setReblogsCount(int reblogsCount) {
    method setFavouritedCount (line 141) | protected void setFavouritedCount(int favouritedCount) {
    method hideStatusInfo (line 145) | protected void hideStatusInfo() {
    method getStatusInfo (line 149) | protected @NonNull TextView getStatusInfo() {
    method setupCollapsedState (line 153) | private void setupCollapsedState(boolean sensitive,
    method showStatusContent (line 179) | public void showStatusContent(boolean show) {
    method toggleExpandedState (line 184) | @Override

FILE: app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java
  class ConversationViewHolder (line 42) | public class ConversationViewHolder extends StatusBaseViewHolder {
    method ConversationViewHolder (line 53) | ConversationViewHolder(View itemView,
    method setupWithConversation (line 69) | void setupWithConversation(
    method setConversationName (line 134) | private void setConversationName(List<ConversationAccountEntity> accou...
    method setAvatars (line 148) | private void setAvatars(List<ConversationAccountEntity> accounts) {
    method setupCollapsedState (line 161) | private void setupCollapsedState(boolean collapsible, boolean collapse...

FILE: app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
  class AppDatabase (line 53) | @Database(
    method accountDao (line 84) | @NonNull public abstract AccountDao accountDao();
    method instanceDao (line 85) | @NonNull public abstract InstanceDao instanceDao();
    method conversationDao (line 86) | @NonNull public abstract ConversationsDao conversationDao();
    method timelineDao (line 87) | @NonNull public abstract TimelineDao timelineDao();
    method draftDao (line 88) | @NonNull public abstract DraftDao draftDao();
    method notificationsDao (line 89) | @NonNull public abstract NotificationsDao notificationsDao();
    method timelineStatusDao (line 90) | @NonNull public abstract TimelineStatusDao timelineStatusDao();
    method timelineAccountDao (line 91) | @NonNull public abstract TimelineAccountDao timelineAccountDao();
    method notificationPolicyDao (line 92) | @NonNull public abstract NotificationPolicyDao notificationPolicyDao();
    method migrate (line 95) | @Override
    method migrate (line 105) | @Override
    method migrate (line 115) | @Override
    method migrate (line 138) | @Override
    method migrate (line 145) | @Override
    method migrate (line 154) | @Override
    method migrate (line 161) | @Override
    method migrate (line 168) | @Override
    method migrate (line 178) | @Override
    method migrate (line 225) | @Override
    method migrate (line 262) | @Override
    method migrate (line 311) | @Override
    method migrate (line 319) | @Override
    method migrate (line 326) | @Override
    method migrate (line 334) | @Override
    method migrate (line 341) | @Override
    method migrate (line 348) | @Override
    method migrate (line 355) | @Override
    method migrate (line 365) | @Override
    method migrate (line 374) | @Override
    method migrate (line 381) | @Override
    method migrate (line 388) | @Override
    method migrate (line 395) | @Override
    method migrate (line 402) | @Override
    class Migration25_26 (line 420) | public static class Migration25_26 extends Migration {
      method Migration25_26 (line 424) | public Migration25_26(@Nullable File oldDraftDirectory) {
      method migrate (line 429) | @Override
    method migrate (line 448) | @Override
    method migrate (line 455) | @Override
    method migrate (line 512) | @Override
    method migrate (line 520) | @Override
    method migrate (line 529) | @Override
    method migrate (line 539) | @Override
    method migrate (line 546) | @Override
    method migrate (line 583) | @Override
    method migrate (line 590) | @Override
    method migrate (line 597) | @Override
    method migrate (line 609) | @Override
    method migrate (line 617) | @Override
    method migrate (line 629) | @Override
    method migrate (line 637) | @Override
    method migrate (line 650) | @Override
    method migrate (line 657) | @Override
    method migrate (line 666) | @Override
    method migrate (line 673) | @Override
    method migrate (line 680) | @Override
    method migrate (line 688) | @Override
    method migrate (line 695) | @Override
    method migrate (line 702) | @Override
    class MIGRATION_49_50 (line 708) | @DeleteColumn(tableName = "AccountEntity", columnName = "activeNotific...
    method migrate (line 716) | @Override
    method migrate (line 723) | @Override
    method migrate (line 732) | @Override
    method migrate (line 854) | @Override
    class MIGRATION_66_68 (line 860) | @DeleteColumn(tableName = "AccountEntity", columnName = "notifications...

FILE: app/src/main/java/com/keylesspalace/tusky/interfaces/ActionButtonActivity.java
  type ActionButtonActivity (line 21) | public interface ActionButtonActivity {
    method getActionButton (line 24) | @Nullable

FILE: app/src/main/java/com/keylesspalace/tusky/util/twittertext/Regex.java
  class Regex (line 14) | public class Regex {
    method Regex (line 16) | protected Regex() {
    method join (line 336) | private static String join(@Nonnull Collection<?> col) {

FILE: app/src/main/java/com/keylesspalace/tusky/util/twittertext/TldLists.java
  class TldLists (line 10) | public final class TldLists {
    method TldLists (line 11) | private TldLists() {
Condensed preview — 1670 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (9,632K chars).
[
  {
    "path": ".editorconfig",
    "chars": 590,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespa"
  },
  {
    "path": ".gitattributes",
    "chars": 53,
    "preview": "* text=auto eol=lf\n\n*.bat text eol=crlf\n*.jar binary\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 23,
    "preview": "open_collective: tusky\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1.bug_report.yml",
    "chars": 1229,
    "preview": "name: Bug Report\ndescription: If something isn't working as expected\nlabels: [bug]\nbody:\n  - type: markdown\n    attribut"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2.feature_request.yml",
    "chars": 591,
    "preview": "name: Feature Request\ndescription: I have a suggestion\nlabels: [enhancement]\nbody:\n  - type: markdown\n    attributes:\n  "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 27,
    "preview": "blank_issues_enabled: true\n"
  },
  {
    "path": ".github/actions/setup/action.yml",
    "chars": 569,
    "preview": "name: 'Setup build environment'\ndescription: 'Sets up an environment for building Tusky'\nruns:\n  using: \"composite\"\n  st"
  },
  {
    "path": ".github/ci-gradle.properties",
    "chars": 910,
    "preview": "#\n# Copyright 2023 Tusky Contributors\n#\n# This file is a part of Tusky.\n#\n# This program is free software; you can redis"
  },
  {
    "path": ".github/renovate.json",
    "chars": 384,
    "preview": "{\n    \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n    \"extends\": [\n        \"config:recommended\"\n    "
  },
  {
    "path": ".github/workflows/check-and-build.yml",
    "chars": 553,
    "preview": "name: Check and build\n\non:\n  pull_request:\n  workflow_call:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      "
  },
  {
    "path": ".github/workflows/deploy-release.yml",
    "chars": 1659,
    "preview": "# When a tag is created, create a release build and upload it to Google Play\n\nname: Deploy release to Google Play\n\non:\n "
  },
  {
    "path": ".github/workflows/deploy-test.yml",
    "chars": 1958,
    "preview": "# Deploy Tusky Nightly on each push to develop\n\nname: Deploy Tusky Nightly to Google Play\n\non:\n  push:\n    branches:\n   "
  },
  {
    "path": ".gitignore",
    "chars": 122,
    "preview": "*.iml\n.gradle\n/local.properties\n/.idea\n.DS_Store\nbuild\n/captures\n.externalNativeBuild\napp/release\napp-release.apk\n.kotli"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 36471,
    "preview": "# Tusky changelog\n\n## Unreleased or Tusky Nightly\n\n### New features and other improvements\n\n### Significant bug fixes\n\n#"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 4474,
    "preview": "# Contributing\n\nThanks for your interest in contributing to Tusky! Here are some informations to help you get started.\n\n"
  },
  {
    "path": "LICENSE.txt",
    "chars": 35147,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "README.md",
    "chars": 608,
    "preview": "This repository has moved to Codeberg: https://codeberg.org/tusky/Tusky\n\n# Tusky\n\n<img src=\"/fastlane/metadata/android/e"
  },
  {
    "path": "app/build.gradle",
    "chars": 6042,
    "preview": "import app.cash.licensee.SpdxId\n\nplugins {\n    alias(libs.plugins.android.application)\n    alias(libs.plugins.google.ksp"
  },
  {
    "path": "app/getGitSha.gradle",
    "chars": 924,
    "preview": "import org.gradle.api.provider.ValueSourceParameters\nimport javax.inject.Inject\n\n// Must wrap this in a ValueSource in o"
  },
  {
    "path": "app/lint-baseline.xml",
    "chars": 27368,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<issues format=\"6\" by=\"lint 8.9.2\" type=\"baseline\" client=\"gradle\" dependencies=\""
  },
  {
    "path": "app/lint.xml",
    "chars": 3366,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Copyright 2023 Tusky Contributors\n  ~\n  ~ This file is a part of Tusky.\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 2777,
    "preview": "# GENERAL OPTIONS\n\n-allowaccessmodification\n\n# Preserve some attributes that may be required for reflection.\n-keepattrib"
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/10.json",
    "chars": 8942,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 10,\n    \"identityHash\": \"69e310ef98c0f305934d25e763ee0140\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/11.json",
    "chars": 16583,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 11,\n    \"identityHash\": \"f5e93302cf53d4250e455b701bea102f\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/12.json",
    "chars": 21645,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 12,\n    \"identityHash\": \"d4d3d4c683ab7f681459b9edab92301c\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/13.json",
    "chars": 21281,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 13,\n    \"identityHash\": \"9a63a3ab2c05004022c350aab0e472c0\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/14.json",
    "chars": 21500,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 14,\n    \"identityHash\": \"b9ca62605345d229ced2bb0c1f2db79b\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/15.json",
    "chars": 21847,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 15,\n    \"identityHash\": \"6a01315ce9f7d402cb61e611140e3c0a\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/16.json",
    "chars": 22069,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 16,\n    \"identityHash\": \"821df8c72aa78a288b4ae9fe2df21dda\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/17.json",
    "chars": 22246,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 17,\n    \"identityHash\": \"4e6bfccf6ec0812dc0bc58d5bc8cf556\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/18.json",
    "chars": 22480,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 18,\n    \"identityHash\": \"33d7d9b8ba14c87b96ce795c337bfc57\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/19.json",
    "chars": 23065,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 19,\n    \"identityHash\": \"84ebd39cba4d6749251d330851b70e36\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/20.json",
    "chars": 23503,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 20,\n    \"identityHash\": \"611700a54bdc155d6bc9d87b8b2af2aa\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/21.json",
    "chars": 23678,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 21,\n    \"identityHash\": \"7570c84ffeb4f90521f91dc7ef3e7da1\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/22.json",
    "chars": 23930,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 22,\n    \"identityHash\": \"eaa3c4d012fe743948343983fe1ae493\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/23.json",
    "chars": 24105,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 23,\n    \"identityHash\": \"03a7436643ef356198742c5f8e054f5f\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/24.json",
    "chars": 24351,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 24,\n    \"identityHash\": \"ea8559bbdf434c7b9086384a9a4cc8e6\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/25.json",
    "chars": 26585,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 25,\n    \"identityHash\": \"e2cb844862443c2c5cc884c11f120d43\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/26.json",
    "chars": 24400,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 26,\n    \"identityHash\": \"14fb3d5743b7a89e8e62463e05f086ab\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/27.json",
    "chars": 24598,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 27,\n    \"identityHash\": \"be914d4eb3f406b6970fef53a925afa1\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/28.json",
    "chars": 25418,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 28,\n    \"identityHash\": \"867026e095d84652026e902709389c00\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/29.json",
    "chars": 25766,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 29,\n    \"identityHash\": \"62c289344334da2db091ad4ba0a49c6a\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/30.json",
    "chars": 26407,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 30,\n    \"identityHash\": \"a75615171612bdfc9e3d4201ebf6071a\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/31.json",
    "chars": 26459,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 31,\n    \"identityHash\": \"a75615171612bdfc9e3d4201ebf6071a\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/32.json",
    "chars": 26687,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 32,\n    \"identityHash\": \"c92343960c9d46d9cfd49f1873cce47d\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/33.json",
    "chars": 26471,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 33,\n    \"identityHash\": \"920a0e0c9a600bd236f6bf959b469c18\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/34.json",
    "chars": 26699,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 34,\n    \"identityHash\": \"7f766d68ab5d72a7988cd81c183e9a9d\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/35.json",
    "chars": 26865,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 35,\n    \"identityHash\": \"9e6c0bb60538683a16c30fa3e1cc24f2\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/36.json",
    "chars": 28038,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 36,\n    \"identityHash\": \"1b7461c291f67fe0b21f77b95de6a6be\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/37.json",
    "chars": 28461,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 37,\n    \"identityHash\": \"11033751d382aa8a1c6fc68833097d35\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/38.json",
    "chars": 28644,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 38,\n    \"identityHash\": \"798fc8d34064eb671c079689d4650ea5\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/39.json",
    "chars": 29012,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 39,\n    \"identityHash\": \"ed3b752a3faec9d092d5ac0a2823d5d5\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/40.json",
    "chars": 30459,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 40,\n    \"identityHash\": \"0423fb3f7d09db5f12023f2f4e7297b5\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/41.json",
    "chars": 30646,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 41,\n    \"identityHash\": \"1de8f20c7f28e1f11b33e7a55137feef\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/42.json",
    "chars": 31195,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 42,\n    \"identityHash\": \"a62399cb3859de7fcbb9bd7053f7cb1d\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/43.json",
    "chars": 31414,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 43,\n    \"identityHash\": \"bf68abe55bb58765da7f9d6f7ef618e2\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/44.json",
    "chars": 31642,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 44,\n    \"identityHash\": \"7b5271980102f35e55438f46777e3d46\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/45.json",
    "chars": 32025,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 45,\n    \"identityHash\": \"cb4d4c0de04e945005adbb43bc534378\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/46.json",
    "chars": 32203,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 46,\n    \"identityHash\": \"3cdfad61c4cf7e1ad5c70783e60e6845\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/47.json",
    "chars": 32416,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 47,\n    \"identityHash\": \"496e1f2135a296e49eef88551ecbdd2c\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/48.json",
    "chars": 32594,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 48,\n    \"identityHash\": \"a394ca5b45df9358fdc4d2eaae69cce3\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/49.json",
    "chars": 32841,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 49,\n    \"identityHash\": \"e7085677596f03c64da3d26e05321a08\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/50.json",
    "chars": 32622,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 50,\n    \"identityHash\": \"4eaf69e915d4a15f021547b725101acd\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/51.json",
    "chars": 32891,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 51,\n    \"identityHash\": \"446158bf571fbd08787628bb829fa3c0\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/52.json",
    "chars": 33120,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 52,\n    \"identityHash\": \"233a8680f540e9a89950da21532ce85d\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/53.json",
    "chars": 33120,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 53,\n    \"identityHash\": \"233a8680f540e9a89950da21532ce85d\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/54.json",
    "chars": 33394,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 54,\n    \"identityHash\": \"c86c3e5ef2c1c5903657a0138b4b2520\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/56.json",
    "chars": 34057,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 56,\n    \"identityHash\": \"1d1eba6d905d2a6e16ae2daa81c0ab4a\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/58.json",
    "chars": 34271,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 58,\n    \"identityHash\": \"1d0e1cdf0b4c3f787333b9abf3b2b26a\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/60.json",
    "chars": 44105,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 60,\n    \"identityHash\": \"1f8ec0c172cc1cae16313d737f6f8e34\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/62.json",
    "chars": 44330,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 62,\n    \"identityHash\": \"f50579baaea33d99c59a34671799682a\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/64.json",
    "chars": 44600,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 64,\n    \"identityHash\": \"12c1f266e9fb1d7fea3dde12866eb338\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/66.json",
    "chars": 44898,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 66,\n    \"identityHash\": \"a17a9b196abd59db5104b46ea19c4d10\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/68.json",
    "chars": 46638,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 68,\n    \"identityHash\": \"45583265bb92757d39163ee6c19dc4e5\",\n    \""
  },
  {
    "path": "app/schemas/com.keylesspalace.tusky.db.AppDatabase/70.json",
    "chars": 46852,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 70,\n    \"identityHash\": \"f1ac7b67aa0a9a279f7f35f5817b6a17\",\n    \""
  },
  {
    "path": "app/src/green/res/values/flavor-colors.xml",
    "chars": 229,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <color name=\"notification_color\">@color/tusky_green</color>\n\n   "
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 10268,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:to"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt",
    "chars": 4688,
    "preview": "package com.keylesspalace.tusky\n\nimport android.content.Intent\nimport android.os.Build\nimport android.os.Bundle\nimport a"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt",
    "chars": 10877,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/BaseActivity.kt",
    "chars": 12734,
    "preview": "/* Copyright 2024 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt",
    "chars": 6945,
    "preview": "/* Copyright 2018 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt",
    "chars": 14481,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt",
    "chars": 2640,
    "preview": "/* Copyright 2018 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt",
    "chars": 11633,
    "preview": "/* Copyright Tusky contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/MainActivity.kt",
    "chars": 49482,
    "preview": "/* Copyright 2020 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/MainViewModel.kt",
    "chars": 7593,
    "preview": "/* Copyright 2024 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/StatusListActivity.kt",
    "chars": 17434,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/TabData.kt",
    "chars": 5733,
    "preview": "/* Copyright 2019 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt",
    "chars": 12470,
    "preview": "/* Copyright 2019 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt",
    "chars": 6657,
    "preview": "/* Copyright 2020 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt",
    "chars": 15254,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/AccountFieldEditAdapter.kt",
    "chars": 3912,
    "preview": "/* Copyright 2018 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt",
    "chars": 2278,
    "preview": "/* Copyright 2019 Levi Bard\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribut"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.kt",
    "chars": 1847,
    "preview": "package com.keylesspalace.tusky.adapter\n\nimport androidx.recyclerview.widget.RecyclerView\nimport com.keylesspalace.tusky"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/EmojiAdapter.kt",
    "chars": 2756,
    "preview": "/* Copyright 2018 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/FilteredStatusViewHolder.kt",
    "chars": 2392,
    "preview": "/* Copyright 2024 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestViewHolder.kt",
    "chars": 5186,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/LoadMoreViewHolder.kt",
    "chars": 1700,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/LoadStateFooterAdapter.kt",
    "chars": 2130,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/LocaleAdapter.kt",
    "chars": 2027,
    "preview": "/* Copyright 2022 Tusky contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/PlaceholderViewHolder.kt",
    "chars": 1949,
    "preview": "/* Copyright 2025 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/PollAdapter.kt",
    "chars": 6233,
    "preview": "/* Copyright 2019 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/PreviewPollOptionsAdapter.kt",
    "chars": 2329,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java",
    "chars": 58926,
    "preview": "package com.keylesspalace.tusky.adapter;\n\nimport static com.keylesspalace.tusky.viewdata.PollViewDataKt.buildDescription"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java",
    "chars": 7837,
    "preview": "package com.keylesspalace.tusky.adapter;\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimp"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java",
    "chars": 8687,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/adapter/TabAdapter.kt",
    "chars": 6290,
    "preview": "/* Copyright 2019 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/appstore/CacheUpdater.kt",
    "chars": 2570,
    "preview": "package com.keylesspalace.tusky.appstore\n\nimport com.keylesspalace.tusky.db.AccountManager\nimport com.keylesspalace.tusk"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/appstore/Events.kt",
    "chars": 1402,
    "preview": "package com.keylesspalace.tusky.appstore\n\nimport com.keylesspalace.tusky.entity.Account\nimport com.keylesspalace.tusky.e"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/appstore/EventsHub.kt",
    "chars": 493,
    "preview": "package com.keylesspalace.tusky.appstore\n\nimport javax.inject.Inject\nimport javax.inject.Singleton\nimport kotlinx.corout"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt",
    "chars": 42821,
    "preview": "/* Copyright 2018 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/AccountFieldAdapter.kt",
    "chars": 2931,
    "preview": "/* Copyright 2018 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/AccountPagerAdapter.kt",
    "chars": 2346,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/AccountViewModel.kt",
    "chars": 12253,
    "preview": "package com.keylesspalace.tusky.components.account\n\nimport android.util.Log\nimport androidx.lifecycle.ViewModel\nimport a"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/list/ListSelectionFragment.kt",
    "chars": 8810,
    "preview": "/* Copyright Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/list/ListsForAccountViewModel.kt",
    "chars": 4777,
    "preview": "/* Copyright 2022 kyori19\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribute "
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaFragment.kt",
    "chars": 8223,
    "preview": "/* Copyright 2022 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaGridAdapter.kt",
    "chars": 5312,
    "preview": "package com.keylesspalace.tusky.components.account.media\n\nimport android.content.Context\nimport android.graphics.Color\ni"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaPagingSource.kt",
    "chars": 1484,
    "preview": "/* Copyright 2022 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaRemoteMediator.kt",
    "chars": 3479,
    "preview": "/* Copyright 2022 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/media/AccountMediaViewModel.kt",
    "chars": 2438,
    "preview": "/* Copyright 2022 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/media/GridSpacingItemDecoration.kt",
    "chars": 1762,
    "preview": "/* Copyright 2022 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/account/media/SquareImageView.kt",
    "chars": 761,
    "preview": "package com.keylesspalace.tusky.components.account.media\n\nimport android.content.Context\nimport android.util.AttributeSe"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListActivity.kt",
    "chars": 3111,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListFragment.kt",
    "chars": 9596,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListPagingSource.kt",
    "chars": 1373,
    "preview": "/* Copyright 2025 Tusky Contributors.\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can r"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListRemoteMediator.kt",
    "chars": 4615,
    "preview": "/* Copyright 2025 Tusky Contributors.\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can r"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountListViewModel.kt",
    "chars": 8853,
    "preview": "/* Copyright 2025 Tusky Contributors.\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can r"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/AccountViewData.kt",
    "chars": 1121,
    "preview": "/* Copyright 2025 Tusky Contributors.\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can r"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/adapter/AccountAdapter.kt",
    "chars": 1934,
    "preview": "/* Copyright 2021 Tusky Contributors.\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can r"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/adapter/BlocksAdapter.kt",
    "chars": 3109,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/adapter/FollowAdapter.kt",
    "chars": 2059,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/adapter/FollowRequestsAdapter.kt",
    "chars": 2361,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/adapter/FollowRequestsHeaderAdapter.kt",
    "chars": 1907,
    "preview": "/* Copyright 2020 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/accountlist/adapter/MutesAdapter.kt",
    "chars": 4023,
    "preview": "/* Copyright 2023 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt",
    "chars": 6953,
    "preview": "/* Copyright 2020 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsActivity.kt",
    "chars": 7477,
    "preview": "/* Copyright 2020 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementsViewModel.kt",
    "chars": 8380,
    "preview": "/* Copyright 2020 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt",
    "chars": 62394,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeAutoCompleteAdapter.kt",
    "chars": 6850,
    "preview": "/* Copyright 2022 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeTokenizer.kt",
    "chars": 3478,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt",
    "chars": 23125,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/ImageDownsizer.kt",
    "chars": 4047,
    "preview": "/* Copyright 2022 Tusky contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/MediaPreviewAdapter.kt",
    "chars": 5553,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/MediaUploader.kt",
    "chars": 13193,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/AddPollDialog.kt",
    "chars": 4946,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/AddPollOptionsAdapter.kt",
    "chars": 3217,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/CaptionDialog.kt",
    "chars": 8135,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/FocusDialog.kt",
    "chars": 4419,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeOptionsView.kt",
    "chars": 2438,
    "preview": "/* Copyright 2018 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeScheduleView.kt",
    "chars": 8681,
    "preview": "/* Copyright 2019 kyori19\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribute "
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/view/EditTextTyped.kt",
    "chars": 3016,
    "preview": "/* Copyright 2018 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/view/FocusIndicatorView.kt",
    "chars": 5061,
    "preview": "package com.keylesspalace.tusky.components.compose.view\n\nimport android.annotation.SuppressLint\nimport android.content.C"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/view/PollPreviewView.kt",
    "chars": 2362,
    "preview": "/* Copyright 2019 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/view/ProgressImageView.kt",
    "chars": 4382,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/compose/view/TootButton.kt",
    "chars": 2373,
    "preview": "/* Copyright 2018 Conny Duck\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistribu"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationEntity.kt",
    "chars": 6200,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationPagingAdapter.kt",
    "chars": 4330,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewData.kt",
    "chars": 3348,
    "preview": "/* Copyright 2022 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java",
    "chars": 8051,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt",
    "chars": 15306,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsRemoteMediator.kt",
    "chars": 3179,
    "preview": "package com.keylesspalace.tusky.components.conversation\n\nimport androidx.paging.ExperimentalPagingApi\nimport androidx.pa"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsViewModel.kt",
    "chars": 6676,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksActivity.kt",
    "chars": 959,
    "preview": "package com.keylesspalace.tusky.components.domainblocks\n\nimport android.os.Bundle\nimport com.keylesspalace.tusky.BaseAct"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksAdapter.kt",
    "chars": 1219,
    "preview": "package com.keylesspalace.tusky.components.domainblocks\n\nimport android.view.LayoutInflater\nimport android.view.ViewGrou"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksFragment.kt",
    "chars": 3631,
    "preview": "package com.keylesspalace.tusky.components.domainblocks\n\nimport android.os.Bundle\nimport android.util.Log\nimport android"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksPagingSource.kt",
    "chars": 633,
    "preview": "package com.keylesspalace.tusky.components.domainblocks\n\nimport androidx.paging.PagingSource\nimport androidx.paging.Pagi"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksRemoteMediator.kt",
    "chars": 1975,
    "preview": "package com.keylesspalace.tusky.components.domainblocks\n\nimport androidx.paging.ExperimentalPagingApi\nimport androidx.pa"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksRepository.kt",
    "chars": 2366,
    "preview": "/*\n * Copyright 2023 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/domainblocks/DomainBlocksViewModel.kt",
    "chars": 2530,
    "preview": "package com.keylesspalace.tusky.components.domainblocks\n\nimport android.view.View\nimport androidx.annotation.StringRes\ni"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftHelper.kt",
    "chars": 7133,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftMediaAdapter.kt",
    "chars": 3948,
    "preview": "/* Copyright 2020 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsActivity.kt",
    "chars": 7641,
    "preview": "/* Copyright 2020 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsAdapter.kt",
    "chars": 3668,
    "preview": "/* Copyright 2021 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/drafts/DraftsViewModel.kt",
    "chars": 2738,
    "preview": "/* Copyright 2020 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterActivity.kt",
    "chars": 14109,
    "preview": "/* Copyright 2024 Tusky contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterViewModel.kt",
    "chars": 8972,
    "preview": "/* Copyright 2024 Tusky contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/filters/FilterExpiration.kt",
    "chars": 1345,
    "preview": "/* Copyright 2024 Tusky contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/filters/FilterExtensions.kt",
    "chars": 1273,
    "preview": "/*\n * Copyright 2023 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/filters/FiltersActivity.kt",
    "chars": 5322,
    "preview": "package com.keylesspalace.tusky.components.filters\n\nimport android.content.DialogInterface.BUTTON_POSITIVE\nimport androi"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/filters/FiltersAdapter.kt",
    "chars": 2116,
    "preview": "package com.keylesspalace.tusky.components.filters\n\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimp"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/filters/FiltersListener.kt",
    "chars": 209,
    "preview": "package com.keylesspalace.tusky.components.filters\n\nimport com.keylesspalace.tusky.entity.Filter\n\ninterface FiltersListe"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/filters/FiltersViewModel.kt",
    "chars": 4679,
    "preview": "package com.keylesspalace.tusky.components.filters\n\nimport android.util.Log\nimport android.view.View\nimport androidx.lif"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt",
    "chars": 6775,
    "preview": "package com.keylesspalace.tusky.components.followedtags\n\nimport android.content.SharedPreferences\nimport android.os.Bund"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsAdapter.kt",
    "chars": 2180,
    "preview": "package com.keylesspalace.tusky.components.followedtags\n\nimport android.view.LayoutInflater\nimport android.view.ViewGrou"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsPagingSource.kt",
    "chars": 637,
    "preview": "package com.keylesspalace.tusky.components.followedtags\n\nimport androidx.paging.PagingSource\nimport androidx.paging.Pagi"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsRemoteMediator.kt",
    "chars": 2022,
    "preview": "package com.keylesspalace.tusky.components.followedtags\n\nimport androidx.paging.ExperimentalPagingApi\nimport androidx.pa"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsViewModel.kt",
    "chars": 1219,
    "preview": "package com.keylesspalace.tusky.components.followedtags\n\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.v"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/instanceinfo/InstanceInfo.kt",
    "chars": 1280,
    "preview": "/* Copyright 2022 Tusky contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/instanceinfo/InstanceInfoRepository.kt",
    "chars": 11215,
    "preview": "/* Copyright 2022 Tusky contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt",
    "chars": 13116,
    "preview": "/* Copyright 2017 Andrew Dawson\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can redistr"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt",
    "chars": 8785,
    "preview": "/* Copyright 2022 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewViewModel.kt",
    "chars": 2891,
    "preview": "/* Copyright 2022 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/notifications/FollowViewHolder.kt",
    "chars": 3859,
    "preview": "/* Copyright 2024 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/notifications/ModerationWarningViewHolder.kt",
    "chars": 1869,
    "preview": "/* Copyright 2025 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationPolicySummaryAdapter.kt",
    "chars": 2988,
    "preview": "/* Copyright 2024 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationTypeMappers.kt",
    "chars": 4245,
    "preview": "/* Copyright 2024 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt",
    "chars": 24759,
    "preview": "/* Copyright 2024 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsPagingAdapter.kt",
    "chars": 10127,
    "preview": "/* Copyright 2024 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  },
  {
    "path": "app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsRemoteMediator.kt",
    "chars": 9550,
    "preview": "/* Copyright 2024 Tusky Contributors\n *\n * This file is a part of Tusky.\n *\n * This program is free software; you can re"
  }
]

// ... and 1470 more files (download for full content)

About this extraction

This page contains the full source code of the Vavassor/Tusky GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1670 files (8.3 MB), approximately 2.3M tokens, and a symbol index with 142 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!