├── app
├── .gitignore
└── src
│ ├── main
│ ├── res
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.webp
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.webp
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.webp
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.webp
│ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.webp
│ │ ├── layout
│ │ │ ├── fragment_splash.xml
│ │ │ ├── view_emiji_list.xml
│ │ │ ├── dialog_circles_explanation.xml
│ │ │ ├── list_item_report_category.xml
│ │ │ ├── activity_main.xml
│ │ │ └── view_people_search_bar.xml
│ │ ├── color
│ │ │ ├── send_ic_state_color.xml
│ │ │ ├── button_src_state_color.xml
│ │ │ └── emoji_chip_background.xml
│ │ ├── drawable
│ │ │ ├── bg_border.xml
│ │ │ ├── bg_border_selected.xml
│ │ │ ├── bg_mention_highlight.xml
│ │ │ ├── ic_unselected.xml
│ │ │ ├── bg_rich_text_menu_button.xml
│ │ │ ├── ic_send.xml
│ │ │ ├── ic_italic.xml
│ │ │ ├── ic_error.xml
│ │ │ ├── ic_reply.xml
│ │ │ ├── ic_strikethrough.xml
│ │ │ ├── ic_text.xml
│ │ │ ├── ic_close.xml
│ │ │ ├── ic_more.xml
│ │ │ ├── ic_fullscreen.xml
│ │ │ ├── ic_poll.xml
│ │ │ ├── ic_phone.xml
│ │ │ ├── ic_image.xml
│ │ │ ├── ic_info.xml
│ │ │ ├── ic_number_list.xml
│ │ │ ├── ic_report.xml
│ │ │ ├── ic_winner.xml
│ │ │ ├── ic_bold.xml
│ │ │ ├── ic_search.xml
│ │ │ ├── ic_add_photo.xml
│ │ │ ├── ic_bullet_list.xml
│ │ │ ├── ic_help.xml
│ │ │ ├── ic_ignore.xml
│ │ │ ├── ic_round_contacts.xml
│ │ │ └── ic_emoji.xml
│ │ ├── values
│ │ │ ├── styles.xml
│ │ │ ├── colors.xml
│ │ │ └── attrs.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ └── ic_launcher.xml
│ │ ├── menu
│ │ │ ├── circles_tab_menu.xml
│ │ │ └── people_tab_menu.xml
│ │ ├── xml
│ │ │ └── provider_paths.xml
│ │ └── navigation
│ │ │ └── nav_graph_bottom_menu.xml
│ └── java
│ │ └── org
│ │ └── futo
│ │ └── circles
│ │ ├── model
│ │ ├── PeopleCategoryTypeArg.kt
│ │ ├── MainStyleBarOption.kt
│ │ ├── DMListItemPayload.kt
│ │ ├── PeopleUserListItemPayload.kt
│ │ ├── StyleBarListItem.kt
│ │ ├── CircleListItemPayload.kt
│ │ ├── ReportCategoryListItem.kt
│ │ ├── SetupCircleListItem.kt
│ │ ├── GroupListItemPayload.kt
│ │ ├── PostItemPayload.kt
│ │ ├── CreatePostContent.kt
│ │ ├── DMListItem.kt
│ │ ├── GroupListItem.kt
│ │ └── CircleListItem.kt
│ │ ├── feature
│ │ ├── timeline
│ │ │ ├── post
│ │ │ │ ├── create
│ │ │ │ │ ├── PostSentListener.kt
│ │ │ │ │ └── PreviewPostListener.kt
│ │ │ │ └── menu
│ │ │ │ │ └── PostMenuListener.kt
│ │ │ ├── list
│ │ │ │ ├── OnLinkClickedListener.kt
│ │ │ │ ├── holder
│ │ │ │ │ ├── VideoPlaybackViewHolder.kt
│ │ │ │ │ └── TimelineLoadingViewHolder.kt
│ │ │ │ ├── OnVideoPlayBackStateListener.kt
│ │ │ │ └── PostOptionsListener.kt
│ │ │ └── data_source
│ │ │ │ └── ReadMessageDataSource.kt
│ │ ├── direct
│ │ │ ├── timeline
│ │ │ │ └── listeners
│ │ │ │ │ ├── SendDmMessageListener.kt
│ │ │ │ │ └── DmOptionsListener.kt
│ │ │ └── tab
│ │ │ │ └── DMViewModel.kt
│ │ ├── circles
│ │ │ └── CirclesViewModel.kt
│ │ ├── groups
│ │ │ └── GroupsViewModel.kt
│ │ ├── share
│ │ │ └── group
│ │ │ │ └── ShareWithGroupActivity.kt
│ │ └── splash
│ │ │ └── SplashFragment.kt
│ │ └── mapping
│ │ └── MatrixUserMapping.kt
│ ├── test
│ └── java
│ │ └── org
│ │ └── futo
│ │ └── circles
│ │ └── ExampleUnitTest.kt
│ ├── gplay
│ └── AndroidManifest.xml
│ └── fdroid
│ └── AndroidManifest.xml
├── auth
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable
│ │ │ │ ├── ic_eu.png
│ │ │ │ ├── ic_us.png
│ │ │ │ ├── explanation_groups.jpg
│ │ │ │ ├── explanation_circles_1.jpeg
│ │ │ │ ├── explanation_circles_2.jpeg
│ │ │ │ ├── explanation_circles_3.jpeg
│ │ │ │ ├── explanation_circles_4.jpeg
│ │ │ │ ├── ic_file.xml
│ │ │ │ ├── ic_info.xml
│ │ │ │ └── ic_lightbulb.xml
│ │ │ ├── values
│ │ │ │ ├── ids.xml
│ │ │ │ └── styles.xml
│ │ │ └── layout
│ │ │ │ └── fragment_empty.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── org
│ │ │ └── futo
│ │ │ └── circles
│ │ │ └── auth
│ │ │ ├── bsspeke
│ │ │ ├── BSSpekeError.kt
│ │ │ └── BSSpekeClientProvider.kt
│ │ │ ├── model
│ │ │ ├── UIAFlowType.kt
│ │ │ ├── AuthUIAScreenNavigationEvent.kt
│ │ │ ├── UIANavigationEvent.kt
│ │ │ ├── DomainSignupFlows.kt
│ │ │ ├── WorkspaceTask.kt
│ │ │ ├── TermsListItem.kt
│ │ │ ├── SubscriptionReceiptData.kt
│ │ │ ├── SetupCirclesListItem.kt
│ │ │ ├── SubscriptionListItem.kt
│ │ │ ├── ValidateUserIdStatus.kt
│ │ │ ├── SwitchUserListItem.kt
│ │ │ ├── SecretKeyData.kt
│ │ │ ├── ConfirmationType.kt
│ │ │ └── CustomUIAuth.kt
│ │ │ ├── credentials
│ │ │ ├── CredentialsProvider.kt
│ │ │ └── CredentialsManager.kt
│ │ │ ├── feature
│ │ │ ├── explanation
│ │ │ │ └── ExplanationDismissListener.kt
│ │ │ ├── uia
│ │ │ │ ├── flow
│ │ │ │ │ └── reauth
│ │ │ │ │ │ └── ReAuthCancellationListener.kt
│ │ │ │ ├── stages
│ │ │ │ │ └── EmptyFragment.kt
│ │ │ │ └── UIADataSourceProvider.kt
│ │ │ ├── sign_up
│ │ │ │ └── SignupSelectDomainListener.kt
│ │ │ ├── log_in
│ │ │ │ └── suggestion
│ │ │ │ │ └── LoginSuggestionListener.kt
│ │ │ └── pass_phrase
│ │ │ │ ├── recovery
│ │ │ │ └── EnterPassPhraseDialogListener.kt
│ │ │ │ └── EncryptionAlgorithmHelper.kt
│ │ │ └── subscriptions
│ │ │ ├── SubscriptionProvider.kt
│ │ │ ├── ItemPurchasedListener.kt
│ │ │ ├── SubscriptionManager.kt
│ │ │ └── IsoPeriod.kt
│ ├── test
│ │ └── java
│ │ │ └── org
│ │ │ └── futo
│ │ │ └── circles
│ │ │ └── auth
│ │ │ └── ExampleUnitTest.kt
│ ├── fdroid
│ │ └── java
│ │ │ └── org
│ │ │ └── futo
│ │ │ └── circles
│ │ │ └── auth
│ │ │ └── di
│ │ │ └── CredentialsModule.kt
│ ├── gplay
│ │ └── java
│ │ │ └── org
│ │ │ └── futo
│ │ │ └── circles
│ │ │ └── auth
│ │ │ └── di
│ │ │ └── CredentialsModule.kt
│ └── androidTest
│ │ └── java
│ │ └── org
│ │ └── futo
│ │ └── circles
│ │ └── auth
│ │ └── ExampleInstrumentedTest.kt
└── proguard-rules.pro
├── core
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ │ └── futo
│ │ │ │ └── circles
│ │ │ │ └── core
│ │ │ │ ├── model
│ │ │ │ ├── MediaType.kt
│ │ │ │ ├── PostListItem.kt
│ │ │ │ ├── RoomInfo.kt
│ │ │ │ ├── TaskStatus.kt
│ │ │ │ ├── PollVoteSummaryData.kt
│ │ │ │ ├── PushData.kt
│ │ │ │ ├── MediaAttachmentInfo.kt
│ │ │ │ ├── PickGalleryMediaResultItem.kt
│ │ │ │ ├── InviteLoadingEvent.kt
│ │ │ │ ├── RoomEventGroupInfo.kt
│ │ │ │ ├── CirclesUserSummary.kt
│ │ │ │ ├── CreatePollContent.kt
│ │ │ │ ├── PollResponseData.kt
│ │ │ │ ├── PollOption.kt
│ │ │ │ ├── SelectableRoomListItem.kt
│ │ │ │ ├── PollState.kt
│ │ │ │ ├── PollContent.kt
│ │ │ │ ├── DmRoomState.kt
│ │ │ │ ├── ReactionsData.kt
│ │ │ │ ├── SharableContent.kt
│ │ │ │ ├── NotifiableEvent.kt
│ │ │ │ ├── GroupedNotificationEvents.kt
│ │ │ │ ├── SelectRoomTypeArg.kt
│ │ │ │ ├── OtherEventContent.kt
│ │ │ │ ├── DiscoveryResponse.kt
│ │ │ │ ├── AccessLevelListItem.kt
│ │ │ │ ├── RoomRequestTypeArg.kt
│ │ │ │ ├── NotificationTestListItem.kt
│ │ │ │ ├── PostContentType.kt
│ │ │ │ ├── ShareUrlTypeArg.kt
│ │ │ │ ├── PostContent.kt
│ │ │ │ ├── MediaFileData.kt
│ │ │ │ ├── GalleryContentListItem.kt
│ │ │ │ ├── AccessLevel.kt
│ │ │ │ ├── InviteNotifiableEvent.kt
│ │ │ │ ├── PostInfo.kt
│ │ │ │ ├── CircleRoomTypeArg.kt
│ │ │ │ ├── Post.kt
│ │ │ │ ├── NotificationAction.kt
│ │ │ │ ├── ResLoadingData.kt
│ │ │ │ └── FilterTimelinesListItem.kt
│ │ │ │ ├── base
│ │ │ │ ├── list
│ │ │ │ │ └── IdEntity.kt
│ │ │ │ ├── DeepLinkIntentHandler.kt
│ │ │ │ ├── ExpandableItemsDataSource.kt
│ │ │ │ ├── Constants.kt
│ │ │ │ └── SingleEventLiveData.kt
│ │ │ │ ├── feature
│ │ │ │ ├── blurhash
│ │ │ │ │ ├── RGBA.kt
│ │ │ │ │ └── ThumbHashImage.kt
│ │ │ │ ├── notifications
│ │ │ │ │ ├── test
│ │ │ │ │ │ └── task
│ │ │ │ │ │ │ ├── TestPushClicker.kt
│ │ │ │ │ │ │ ├── NotificationQuickFix.kt
│ │ │ │ │ │ │ ├── TestPushDisplayEvenReceiver.kt
│ │ │ │ │ │ │ ├── NotificationTestsProvider.kt
│ │ │ │ │ │ │ └── TestNotificationReceiver.kt
│ │ │ │ │ ├── GuardServiceStarter.kt
│ │ │ │ │ ├── KeepInternalDistributor.kt
│ │ │ │ │ ├── FcmHelper.kt
│ │ │ │ │ ├── ProcessedEvent.kt
│ │ │ │ │ ├── NotificationActionIds.kt
│ │ │ │ │ └── CircularCache.kt
│ │ │ │ ├── select_users
│ │ │ │ │ └── SelectUsersListener.kt
│ │ │ │ ├── room
│ │ │ │ │ ├── manage_members
│ │ │ │ │ │ ├── change_role
│ │ │ │ │ │ │ └── ChangeAccessLevelListener.kt
│ │ │ │ │ │ └── ManageMembersOptionsListener.kt
│ │ │ │ │ ├── select
│ │ │ │ │ │ ├── interfaces
│ │ │ │ │ │ │ ├── RoomsListener.kt
│ │ │ │ │ │ │ ├── SelectRoomsListener.kt
│ │ │ │ │ │ │ └── RoomsPicker.kt
│ │ │ │ │ │ ├── SelectRoomsViewModel.kt
│ │ │ │ │ │ └── list
│ │ │ │ │ │ │ └── SelectRoomsAdapter.kt
│ │ │ │ │ └── create
│ │ │ │ │ │ └── CreateRoomProgressListener.kt
│ │ │ │ ├── share
│ │ │ │ │ └── ShareUrl.kt
│ │ │ │ ├── markdown
│ │ │ │ │ ├── mentions
│ │ │ │ │ │ └── plugin
│ │ │ │ │ │ │ └── MentionNode.kt
│ │ │ │ │ └── span
│ │ │ │ │ │ └── MentionSpan.kt
│ │ │ │ ├── picker
│ │ │ │ │ ├── gallery
│ │ │ │ │ │ ├── media
│ │ │ │ │ │ │ └── list
│ │ │ │ │ │ │ │ └── holder
│ │ │ │ │ │ │ │ ├── GalleryTimelineItemViewHolder.kt
│ │ │ │ │ │ │ │ └── GalleryTimelineLoadingViewHolder.kt
│ │ │ │ │ │ └── rooms
│ │ │ │ │ │ │ └── PickGalleryViewModel.kt
│ │ │ │ │ └── GetContentWithMultiFilter.kt
│ │ │ │ ├── textDrawable
│ │ │ │ │ └── ColorGenerator.kt
│ │ │ │ ├── user
│ │ │ │ │ └── UserOptionsDataSource.kt
│ │ │ │ └── circles
│ │ │ │ │ └── following
│ │ │ │ │ └── list
│ │ │ │ │ └── FollowingAdapter.kt
│ │ │ │ ├── update
│ │ │ │ ├── AppUpdateProvider.kt
│ │ │ │ └── CirclesAppUpdateManager.kt
│ │ │ │ ├── extensions
│ │ │ │ ├── StringExtensions.kt
│ │ │ │ ├── HiltExtensions.kt
│ │ │ │ ├── TextInputLayoutExtensions.kt
│ │ │ │ ├── FileExtensions.kt
│ │ │ │ ├── NavControllerExtensions.kt
│ │ │ │ ├── RoomSummaryExtensions.kt
│ │ │ │ ├── ViewModelExtensions.kt
│ │ │ │ ├── SearchViewExtensions.kt
│ │ │ │ ├── MatrixUserExtensions.kt
│ │ │ │ ├── TimelineEventExtensions.kt
│ │ │ │ └── MediaContentDataExtensions.kt
│ │ │ │ ├── provider
│ │ │ │ ├── MatrixNotificationSetupListener.kt
│ │ │ │ └── MatrixInstanceProvider.kt
│ │ │ │ ├── mapping
│ │ │ │ └── MatrixUserMapping.kt
│ │ │ │ ├── utils
│ │ │ │ ├── HomeServerUtils.kt
│ │ │ │ └── UserIdUtils.kt
│ │ │ │ ├── glide
│ │ │ │ └── LocalFileHelper.kt
│ │ │ │ └── view
│ │ │ │ └── NetworkRequiredButton.kt
│ │ ├── res
│ │ │ ├── animator
│ │ │ │ ├── nav_default_enter_anim.xml
│ │ │ │ ├── nav_default_exit_anim.xml
│ │ │ │ ├── nav_default_pop_enter_anim.xml
│ │ │ │ └── nav_default_pop_exit_anim.xml
│ │ │ ├── values
│ │ │ │ ├── ids.xml
│ │ │ │ ├── dimen.xml
│ │ │ │ └── attrs.xml
│ │ │ ├── drawable
│ │ │ │ ├── bg_border.xml
│ │ │ │ ├── ic_unselected.xml
│ │ │ │ ├── ic_keyboard_arrow_down.xml
│ │ │ │ ├── ic_add.xml
│ │ │ │ ├── ic_play_round.xml
│ │ │ │ ├── ic_error.xml
│ │ │ │ ├── ic_resend.xml
│ │ │ │ ├── ic_video.xml
│ │ │ │ ├── ic_download.xml
│ │ │ │ ├── ic_check.xml
│ │ │ │ ├── ic_keyboard_arrow_up.xml
│ │ │ │ ├── ic_app_version.xml
│ │ │ │ ├── ic_create.xml
│ │ │ │ ├── ic_close.xml
│ │ │ │ ├── ic_check_circle.xml
│ │ │ │ ├── ic_direct_messages.xml
│ │ │ │ ├── ic_gallery.xml
│ │ │ │ ├── ic_phone.xml
│ │ │ │ ├── ic_logout.xml
│ │ │ │ ├── ic_info.xml
│ │ │ │ ├── ic_invite.xml
│ │ │ │ ├── ic_filter.xml
│ │ │ │ ├── ic_notifications.xml
│ │ │ │ ├── ic_lock.xml
│ │ │ │ ├── ic_seen.xml
│ │ │ │ ├── ic_delete.xml
│ │ │ │ ├── ic_lock_open.xml
│ │ │ │ ├── ic_knock_requests.xml
│ │ │ │ ├── ic_switch_user.xml
│ │ │ │ ├── ic_deactivate_account.xml
│ │ │ │ ├── ic_edit.xml
│ │ │ │ ├── ic_reload.xml
│ │ │ │ ├── ic_add_photo.xml
│ │ │ │ ├── ic_curved_arrow.xml
│ │ │ │ ├── ic_unfollow.xml
│ │ │ │ ├── ic_photo.xml
│ │ │ │ ├── ic_mention.xml
│ │ │ │ ├── ic_notifications_off.xml
│ │ │ │ ├── ic_ban.xml
│ │ │ │ └── ic_person_remove.xml
│ │ │ ├── anim
│ │ │ │ ├── alpha_show.xml
│ │ │ │ ├── slide_in.xml
│ │ │ │ └── slide_out.xml
│ │ │ ├── layout
│ │ │ │ ├── list_item_invite_header.xml
│ │ │ │ ├── fragment_pick_gallery.xml
│ │ │ │ ├── list_item_invite_member.xml
│ │ │ │ ├── list_item_no_results.xml
│ │ │ │ ├── view_spinner_item.xml
│ │ │ │ ├── list_item_timeline_loading.xml
│ │ │ │ ├── list_item_chip.xml
│ │ │ │ ├── dialog_loading.xml
│ │ │ │ ├── list_item_access_level.xml
│ │ │ │ └── list_item_invite_notification.xml
│ │ │ ├── xml
│ │ │ │ └── bg_chip.xml
│ │ │ ├── menu
│ │ │ │ ├── user_menu.xml
│ │ │ │ └── timeline_menu.xml
│ │ │ ├── values-night
│ │ │ │ └── color.xml
│ │ │ └── navigation
│ │ │ │ ├── filter_timelines_nav_graph.xml
│ │ │ │ └── create_room_nav_graph.xml
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── org
│ │ │ └── futo
│ │ │ └── circles
│ │ │ └── core
│ │ │ └── ExampleUnitTest.kt
│ ├── fdroid
│ │ └── java
│ │ │ └── org
│ │ │ └── futo
│ │ │ └── circles
│ │ │ └── core
│ │ │ └── di
│ │ │ └── AppUpdateModule.kt
│ ├── gplay
│ │ └── java
│ │ │ └── org
│ │ │ └── futo
│ │ │ └── circles
│ │ │ └── core
│ │ │ └── di
│ │ │ └── AppUpdateModule.kt
│ └── androidTest
│ │ └── java
│ │ └── org
│ │ └── futo
│ │ └── circles
│ │ └── core
│ │ └── ExampleInstrumentedTest.kt
└── proguard-rules.pro
├── gallery
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ └── styles.xml
│ │ │ ├── menu
│ │ │ │ ├── photos_tab_menu.xml
│ │ │ │ └── gallery_image_menu.xml
│ │ │ ├── transition
│ │ │ │ ├── grid_exit_transition.xml
│ │ │ │ └── image_shared_element_transition.xml
│ │ │ ├── drawable
│ │ │ │ ├── ic_check_circle.xml
│ │ │ │ ├── ic_create.xml
│ │ │ │ └── ic_backup.xml
│ │ │ └── layout
│ │ │ │ └── fragment_select_galleries.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── org
│ │ │ └── futo
│ │ │ └── circles
│ │ │ └── gallery
│ │ │ ├── model
│ │ │ ├── MediaFolderListItem.kt
│ │ │ └── MediaToBackupItem.kt
│ │ │ └── feature
│ │ │ ├── PhotosViewModel.kt
│ │ │ ├── select
│ │ │ └── SelectGalleriesViewModel.kt
│ │ │ └── share
│ │ │ └── UploadToGalleryActivity.kt
│ └── test
│ │ └── java
│ │ └── org
│ │ └── futo
│ │ └── circles
│ │ └── gallery
│ │ └── ExampleUnitTest.kt
└── proguard-rules.pro
├── settings
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── org
│ │ │ │ └── futo
│ │ │ │ └── circles
│ │ │ │ └── settings
│ │ │ │ ├── SessionHolderActivity.kt
│ │ │ │ ├── model
│ │ │ │ ├── QrState.kt
│ │ │ │ └── ActiveSubscriptionInfo.kt
│ │ │ │ └── view
│ │ │ │ └── EditEmailView.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ ├── ic_email.xml
│ │ │ ├── ic_payment.xml
│ │ │ ├── ic_key.xml
│ │ │ ├── ic_verified.xml
│ │ │ ├── ic_round_photo_library.xml
│ │ │ └── ic_unverified.xml
│ │ │ └── layout
│ │ │ └── activity_qr_scanner.xml
│ ├── test
│ │ └── java
│ │ │ └── org
│ │ │ └── futo
│ │ │ └── circles
│ │ │ └── settings
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── org
│ │ └── futo
│ │ └── circles
│ │ └── settings
│ │ └── ExampleInstrumentedTest.kt
└── proguard-rules.pro
├── fastlane
├── metadata
│ └── android
│ │ └── en-US
│ │ ├── title.txt
│ │ ├── short_description.txt
│ │ ├── changelogs
│ │ ├── 4401.txt
│ │ ├── 33.txt
│ │ ├── 27.txt
│ │ ├── 29.txt
│ │ ├── 24.txt
│ │ ├── 34.txt
│ │ ├── 28.txt
│ │ ├── 30.txt
│ │ ├── 4301.txt
│ │ ├── 3701.txt
│ │ ├── 31.txt
│ │ ├── 25.txt
│ │ ├── 4201.txt
│ │ ├── 4001.txt
│ │ ├── 3901.txt
│ │ ├── 3501.txt
│ │ ├── 3601.txt
│ │ ├── 3801.txt
│ │ ├── 4101.txt
│ │ └── 32.txt
│ │ ├── images
│ │ ├── icon.png
│ │ ├── featureGraphic.jpeg
│ │ └── phoneScreenshots
│ │ │ ├── 1_en-US.png
│ │ │ ├── 2_en-US.png
│ │ │ ├── 3_en-US.png
│ │ │ ├── 4_en-US.png
│ │ │ ├── 5_en-US.png
│ │ │ ├── 6_en-US.png
│ │ │ └── 7_en-US.png
│ │ └── full_description.txt
└── Appfile
├── Gemfile
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── resources
└── img
│ ├── f-droid-badge.png
│ └── google-play-badge.png
├── .github
└── ISSUE_TEMPLATE
│ └── config.yml
├── modules_release_clean.sh
└── settings.gradle.kts
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/auth/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/auth/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gallery/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/gallery/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/settings/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/settings/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | Circles
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "fastlane"
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | Secure social sharing for friends and families
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/4401.txt:
--------------------------------------------------------------------------------
1 | - Direct messages
2 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/33.txt:
--------------------------------------------------------------------------------
1 | - New default domains
2 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/resources/img/f-droid-badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/resources/img/f-droid-badge.png
--------------------------------------------------------------------------------
/resources/img/google-play-badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/resources/img/google-play-badge.png
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/ic_eu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/auth/src/main/res/drawable/ic_eu.png
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/ic_us.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/auth/src/main/res/drawable/ic_us.png
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/MediaType.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | enum class MediaType { Image, Video }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/27.txt:
--------------------------------------------------------------------------------
1 | v1.0.17
2 | - App No Internet behavior
3 | - Knock requests managing
4 | - Android 14 support
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/29.txt:
--------------------------------------------------------------------------------
1 | - Rust crypto SDK
2 | - New Circles logo
3 | - Blur images in invitations from unknown users
--------------------------------------------------------------------------------
/auth/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/24.txt:
--------------------------------------------------------------------------------
1 | v1.0.15
2 | - new encryption algorithm
3 | - timeline thumbnails
4 | - thumbhash for timeline placeholders
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/34.txt:
--------------------------------------------------------------------------------
1 | - New default domains
2 | - circles.futo.org domain for deep links
3 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/auth/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/explanation_groups.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/auth/src/main/res/drawable/explanation_groups.jpg
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/bsspeke/BSSpekeError.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.bsspeke
2 |
3 | class BSSpekeError(override val message: String) : Exception()
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/UIAFlowType.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | enum class UIAFlowType { Login, Signup, ReAuth, ForgotPassword }
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/explanation_circles_1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/auth/src/main/res/drawable/explanation_circles_1.jpeg
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/explanation_circles_2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/auth/src/main/res/drawable/explanation_circles_2.jpeg
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/explanation_circles_3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/auth/src/main/res/drawable/explanation_circles_3.jpeg
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/explanation_circles_4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/auth/src/main/res/drawable/explanation_circles_4.jpeg
--------------------------------------------------------------------------------
/core/src/main/res/animator/nav_default_enter_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/core/src/main/res/animator/nav_default_exit_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/gallery/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 57dp
4 |
--------------------------------------------------------------------------------
/settings/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/PeopleCategoryTypeArg.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | enum class PeopleCategoryTypeArg { Followers, Following, Other, Ignored }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/base/list/IdEntity.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.base.list
2 |
3 | interface IdEntity {
4 | val id: IdClass
5 | }
--------------------------------------------------------------------------------
/core/src/main/res/animator/nav_default_pop_enter_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/core/src/main/res/animator/nav_default_pop_exit_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/28.txt:
--------------------------------------------------------------------------------
1 | v1.0.18
2 | - "Help" menu item for Groups and Circles
3 | - New share room url formatting
4 | - Knock requests "reason" message
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/base/DeepLinkIntentHandler.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.base
2 |
3 | interface DeepLinkIntentHandler {
4 | fun onNewIntent()
5 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PostListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/30.txt:
--------------------------------------------------------------------------------
1 | - Rust crypto SDK
2 | - New Circles logo
3 | - Blur images in invitations from unknown users
4 | - Fix Kotlin to Rust migration
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/featureGraphic.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/fastlane/metadata/android/en-US/images/featureGraphic.jpeg
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/RoomInfo.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | data class RoomInfo(
4 | val title: String,
5 | val avatarUrl: String
6 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/blurhash/RGBA.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.blurhash
2 |
3 | data class RGBA(var r: Float, var g: Float, var b: Float, var a: Float)
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/4301.txt:
--------------------------------------------------------------------------------
1 | - Simplified Sign up flow
2 | - Fixed crash on Creating new post
3 | - Onboarding design updates
4 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/TaskStatus.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | enum class TaskStatus {
4 | IDLE,
5 | RUNNING,
6 | SUCCESS,
7 | FAILED
8 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/5_en-US.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/6_en-US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/6_en-US.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/7_en-US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/circles-project/circles-android/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/7_en-US.png
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/timeline/post/create/PostSentListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.timeline.post.create
2 |
3 | interface PostSentListener {
4 | fun onPostSent()
5 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PollVoteSummaryData.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | data class PollVoteSummaryData(
4 | val total: Int,
5 | val percentage: Double
6 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/blurhash/ThumbHashImage.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.blurhash
2 |
3 | data class ThumbHashImage(var width: Int, var height: Int, var rgba: ByteArray)
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/update/AppUpdateProvider.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.update
2 |
3 | interface AppUpdateProvider {
4 |
5 | fun getManager(): CirclesAppUpdateManager?
6 |
7 | }
--------------------------------------------------------------------------------
/core/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/MainStyleBarOption.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | enum class MainStyleBarOption {
4 | Media,
5 | Emoji,
6 | Mention,
7 | Link,
8 | TextStyle
9 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/3701.txt:
--------------------------------------------------------------------------------
1 | - Email address management
2 | - New People tab
3 | - Forgot password
4 | - Configurable default user power level for room
5 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/timeline/list/OnLinkClickedListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.timeline.list
2 |
3 |
4 | interface OnLinkClickedListener {
5 | fun onLinkClicked(url: String)
6 | }
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/credentials/CredentialsProvider.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.credentials
2 |
3 | interface CredentialsProvider {
4 |
5 | fun getManager(): CredentialsManager?
6 |
7 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PushData.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | data class PushData(
4 | val eventId: String?,
5 | val roomId: String?,
6 | val unread: Int?,
7 | )
8 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/31.txt:
--------------------------------------------------------------------------------
1 | - Support for refresh tokens
2 | - Fixed markdown editor
3 | - Ability to change poll vote
4 | - Fixed Bcrypt backup restoration
5 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/feature/explanation/ExplanationDismissListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.feature.explanation
2 |
3 | interface ExplanationDismissListener {
4 |
5 | fun onDismissPopUp()
6 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/test/task/TestPushClicker.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications.test.task
2 |
3 | interface TestPushClicker {
4 | fun onTestPushClicked()
5 | }
--------------------------------------------------------------------------------
/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | json_key_file("google_play_api_key.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
2 | package_name("org.futo.circles") # e.g. com.krausefx.app
3 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/feature/uia/flow/reauth/ReAuthCancellationListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.feature.uia.flow.reauth
2 |
3 | interface ReAuthCancellationListener {
4 | fun onReAuthCanceled()
5 | }
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/AuthUIAScreenNavigationEvent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | enum class AuthUIAScreenNavigationEvent {
4 | Home,
5 | ConfigureWorkspace,
6 | PassPhrase
7 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/GuardServiceStarter.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications
2 |
3 | interface GuardServiceStarter {
4 | fun start() {}
5 | fun stop() {}
6 | }
7 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/select_users/SelectUsersListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.select_users
2 |
3 | interface SelectUsersListener {
4 | fun onUserSelected(usersIds: List)
5 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/MediaAttachmentInfo.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | data class MediaAttachmentInfo(
4 | val name: String,
5 | val size: Long,
6 | val mimeType: String
7 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PickGalleryMediaResultItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | data class PickGalleryMediaResultItem(
4 | val uriString: String,
5 | val mediaTypeOrdinal: Int
6 | )
--------------------------------------------------------------------------------
/settings/src/main/java/org/futo/circles/settings/SessionHolderActivity.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.settings
2 |
3 | interface SessionHolderActivity {
4 | fun clearSessionAndRestart()
5 |
6 | fun stopSyncAndRestart()
7 | }
--------------------------------------------------------------------------------
/auth/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/25.txt:
--------------------------------------------------------------------------------
1 | v1.0.16
2 | - People space
3 | - Configure Workspace
4 | - Removed System notices
5 | - Circle/Group explanation dialogs
6 | - Offline browsing of People tab
7 | - Raw recovery key support
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/4201.txt:
--------------------------------------------------------------------------------
1 | - Removed Jdenticon user's icon placeholder
2 | - Added "Invite to follow me"
3 | - Added "Requests for invitation" on Circles/Groups tabs
4 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/test/task/NotificationQuickFix.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications.test.task
2 |
3 | abstract class NotificationQuickFix {
4 | abstract fun runFix()
5 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/feature/sign_up/SignupSelectDomainListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.feature.sign_up
2 |
3 | interface SignupSelectDomainListener {
4 |
5 | fun onSignupDomainSelected(domain: String)
6 |
7 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/4001.txt:
--------------------------------------------------------------------------------
1 | - Fixed create group/circle/gallery navigation
2 | - Share poll as image
3 | - Improved offline app browsing experience
4 | - Shared Galleries section
5 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/test/task/TestPushDisplayEvenReceiver.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications.test.task
2 |
3 | interface TestPushDisplayEvenReceiver {
4 | fun onTestPushDisplayed()
5 | }
--------------------------------------------------------------------------------
/gallery/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/InviteLoadingEvent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 |
4 | data class InviteLoadingEvent(
5 | val userId: String = "",
6 | val roomName: String = "",
7 | val isLoading: Boolean = true
8 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/update/CirclesAppUpdateManager.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.update
2 |
3 | import android.app.Activity
4 |
5 | interface CirclesAppUpdateManager {
6 | fun launchUpdateIfAvailable(activity: Activity)
7 |
8 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/3901.txt:
--------------------------------------------------------------------------------
1 | - Remove BCrypt backup support
2 | - Show all timeline events types with dev mode enabled
3 | - Improve paging for timeline
4 | - App update api (Google Play version)
5 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/StringExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import android.util.Patterns
4 |
5 | fun CharSequence?.isValidEmail() =
6 | !isNullOrEmpty() && Patterns.EMAIL_ADDRESS.matcher(this).matches()
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/feature/uia/stages/EmptyFragment.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.feature.uia.stages
2 |
3 | import androidx.fragment.app.Fragment
4 | import org.futo.circles.auth.R
5 |
6 | class EmptyFragment : Fragment(R.layout.fragment_empty)
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/test/task/NotificationTestsProvider.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications.test.task
2 |
3 | interface NotificationTestsProvider {
4 | fun getTestsList(): List
5 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/3501.txt:
--------------------------------------------------------------------------------
1 | - Fixed posting replies
2 | - UnifiedPush as default distributor(F-Droid)
3 | - Fixed registering UnifiedPush for multiple accounts
4 | - Fixed markdown rendering after switching user
5 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/DMListItemPayload.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | data class DMListItemPayload(
4 | val timestamp: Long?,
5 | val unreadCount: Int?,
6 | val userName: String?,
7 | val avatarUrl: String?,
8 | val userId: String
9 | )
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/PeopleUserListItemPayload.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | import org.futo.circles.core.model.CirclesUserSummary
4 |
5 | data class PeopleUserListItemPayload(
6 | val user: CirclesUserSummary?,
7 | val categoryCount: Int?
8 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/RoomEventGroupInfo.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 |
4 | data class RoomEventGroupInfo(
5 | val roomId: String,
6 | val roomDisplayName: String = ""
7 | ) {
8 | var isUpdated: Boolean = false
9 | }
10 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/feature/log_in/suggestion/LoginSuggestionListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.feature.log_in.suggestion
2 |
3 | interface LoginSuggestionListener {
4 |
5 | fun onLoginSuggestionApplied(userId: String, isForgotPassword: Boolean)
6 |
7 | }
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/UIANavigationEvent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 |
4 | enum class UIANavigationEvent {
5 | TokenValidation,
6 | Subscription,
7 | AcceptTerm,
8 | ValidateEmail,
9 | Password,
10 | Username
11 | }
--------------------------------------------------------------------------------
/gallery/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/color/send_ic_state_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/room/manage_members/change_role/ChangeAccessLevelListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.room.manage_members.change_role
2 |
3 | interface ChangeAccessLevelListener {
4 | fun onChangeAccessLevel(userId: String, levelValue: Int)
5 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Feb 14 14:59:49 EET 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/timeline/list/holder/VideoPlaybackViewHolder.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.timeline.list.holder
2 |
3 | interface VideoPlaybackViewHolder : ImageMediaViewHolder {
4 |
5 | fun stopVideo(shouldNotify: Boolean = true)
6 |
7 | fun playVideo()
8 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/3601.txt:
--------------------------------------------------------------------------------
1 | - Limit displayed aspect ratios for media posts
2 | - Removed Create room delay
3 | - Fixed Change password flow
4 | - Inline Markdown fixes
5 | - Fixed views count on post
6 | - Fixed screens state saving
7 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/StyleBarListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 | data class StyleBarListItem(
6 | override val id: Int,
7 | val iconResId: Int,
8 | val isSelected: Boolean = false
9 | ) : IdEntity
--------------------------------------------------------------------------------
/app/src/main/res/color/button_src_state_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/3801.txt:
--------------------------------------------------------------------------------
1 | - Circle's timelines filter
2 | - Screens animation
3 | - Credentials manager to save/autofill password
4 | - Adaptive app icon
5 | - Video playback in timeline post
6 | - What's new dialog
7 | - Mutual users section
8 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/CircleListItemPayload.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | data class CircleListItemPayload(
4 | val followersCount: Int?,
5 | val followedByCount: Int?,
6 | val unreadCount: Int?,
7 | val knocksCount: Int?,
8 | val needUpdateFullItem: Boolean
9 | )
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/ReportCategoryListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 | data class ReportCategoryListItem(
6 | override val id: Int,
7 | val name: String,
8 | val isSelected: Boolean = false
9 | ) : IdEntity
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/HiltExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import androidx.lifecycle.SavedStateHandle
4 |
5 | fun SavedStateHandle.getOrThrow(key: String): T =
6 | this[key] ?: throw IllegalArgumentException("SavedStateHandle param $key is missing")
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/CirclesUserSummary.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 | data class CirclesUserSummary(
6 | override val id: String,
7 | val name: String,
8 | val avatarUrl: String
9 | ) : IdEntity
--------------------------------------------------------------------------------
/app/src/main/res/color/emoji_chip_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/CreatePollContent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.matrix.android.sdk.api.session.room.model.message.PollType
4 |
5 | data class CreatePollContent(
6 | val pollType: PollType,
7 | val question: String,
8 | val options: List
9 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PollResponseData.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | data class PollResponseData(
4 | val myVote: String?,
5 | val votes: Map?,
6 | val totalVotes: Int,
7 | val winnerVoteCount: Int,
8 | val isClosed: Boolean
9 | )
--------------------------------------------------------------------------------
/gallery/src/main/res/menu/photos_tab_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/DomainSignupFlows.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | import org.matrix.android.sdk.api.auth.registration.Stage
4 |
5 | data class DomainSignupFlows(
6 | val domain: String,
7 | val freeStages: List?,
8 | val subscriptionStages: List?
9 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/room/select/interfaces/RoomsListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.room.select.interfaces
2 |
3 | import org.futo.circles.core.model.SelectableRoomListItem
4 |
5 | interface RoomsListener {
6 | fun onRoomsListChanged(rooms: List)
7 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PollOption.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | data class PollOption(
4 | val optionId: String,
5 | val optionAnswer: String,
6 | val voteCount: Int,
7 | val voteProgress: Int,
8 | val isMyVote: Boolean,
9 | val isWinner: Boolean
10 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/SelectableRoomListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 | data class SelectableRoomListItem(
6 | override val id: String,
7 | val info: RoomInfo,
8 | val isSelected: Boolean
9 | ) : IdEntity
--------------------------------------------------------------------------------
/core/src/main/res/drawable/bg_border.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/WorkspaceTask.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | import android.net.Uri
4 | import org.futo.circles.core.model.CirclesRoom
5 |
6 | data class WorkspaceTask(
7 | val room: CirclesRoom,
8 | val name: String? = null,
9 | val uri: Uri? = null
10 | )
11 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/room/select/interfaces/SelectRoomsListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.room.select.interfaces
2 |
3 | import org.futo.circles.core.model.SelectableRoomListItem
4 |
5 | interface SelectRoomsListener {
6 | fun onRoomsSelected(rooms: List)
7 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PollState.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | enum class PollState { Sending, Ready, Voted, Ended }
4 |
5 | fun PollState.canEdit() = this == PollState.Sending || this == PollState.Ready
6 |
7 | fun PollState.canVote() = this != PollState.Sending && this != PollState.Ended
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/provider/MatrixNotificationSetupListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.provider
2 |
3 | import org.matrix.android.sdk.api.session.Session
4 |
5 | interface MatrixNotificationSetupListener {
6 |
7 | fun onStartWithSession(session: Session)
8 |
9 | fun onStop()
10 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_border_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_mention_highlight.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/settings/src/main/java/org/futo/circles/settings/model/QrState.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.settings.model
2 |
3 | sealed class QrState
4 |
5 | data object QrLoading : QrState()
6 |
7 | data class QrReady(val qrText: String) : QrState()
8 |
9 | data object QrSuccess : QrState()
10 |
11 | data object QrCanceled : QrState()
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/TermsListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 | data class TermsListItem(
6 | override val id: Int,
7 | val name: String,
8 | val url: String,
9 | val isChecked: Boolean = false
10 | ) : IdEntity
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PollContent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | data class PollContent(
4 | val question: String,
5 | val state: PollState,
6 | val totalVotes: Int,
7 | val options: List,
8 | val isClosedType: Boolean
9 | ) : PostContent(PostContentType.POLL_CONTENT)
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/DmRoomState.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | sealed class DmRoomState
4 |
5 | data class DmConnected(val roomId: String) : DmRoomState()
6 | data class DmHasInvite(val roomId: String) : DmRoomState()
7 | data object DmInviteSent : DmRoomState()
8 | data object DmNotFound : DmRoomState()
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/ReactionsData.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 | data class ReactionsData(
6 | val key: String,
7 | val count: Int,
8 | val addedByMe: Boolean
9 | ) : IdEntity {
10 | override val id: String = key
11 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/4101.txt:
--------------------------------------------------------------------------------
1 | - Support of dehydrated devices
2 | - Profile updates via presence system
3 | - Post composer awaits for post to be sent
4 | - Removed Connections
5 | - Removed Gallery (still available in advanced settings)
6 | - Replaced Configure Workspace with new setup flow
7 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/share/ShareUrl.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.share
2 |
3 | import org.futo.circles.core.model.ShareUrlTypeArg
4 |
5 | const val BASE_SHARE_URL = "https://circles.futo.org/"
6 |
7 | fun buildShareRoomUrl(type: ShareUrlTypeArg, roomId: String) =
8 | BASE_SHARE_URL + type.typeKey + "/$roomId"
9 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/SharableContent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import android.net.Uri
4 |
5 | sealed class ShareableContent
6 |
7 | data class TextShareable(val text: String) : ShareableContent()
8 | data class MediaShareable(val uriToFile: Uri, val mimeType: String) : ShareableContent()
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/direct/timeline/listeners/SendDmMessageListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.direct.timeline.listeners
2 |
3 | interface SendDmMessageListener {
4 |
5 | fun onAddEmojiToMessageClicked()
6 |
7 | fun onSendTextMessageClicked(message: String)
8 |
9 | fun onSendMediaButtonClicked()
10 |
11 | }
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/SubscriptionReceiptData.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | data class SubscriptionReceiptData(
4 | val productId: String,
5 | val purchaseToken: String,
6 | val orderId: String,
7 | val packageName: String,
8 | val purchaseTime: Long,
9 | val isAutoRenewing: Boolean
10 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/TextInputLayoutExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import com.google.android.material.textfield.TextInputLayout
4 |
5 | fun TextInputLayout.getText(trim: Boolean = true): String {
6 | val text = editText?.text?.toString() ?: ""
7 | return if (trim) text.trim() else text
8 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/room/select/interfaces/RoomsPicker.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.room.select.interfaces
2 |
3 | import org.futo.circles.core.model.SelectableRoomListItem
4 |
5 | interface RoomsPicker {
6 | var selectRoomsListener: SelectRoomsListener?
7 | fun getSelectedRooms(): List
8 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/SetupCircleListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | import android.net.Uri
4 | import org.futo.circles.core.base.list.IdEntity
5 |
6 | data class SetupCircleListItem(
7 | override val id: Int,
8 | val name: String,
9 | val userName: String,
10 | val coverUri: Uri? = null
11 | ) : IdEntity
--------------------------------------------------------------------------------
/core/src/main/res/values/dimen.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1dp
4 | 24dp
5 | 100dp
6 | 120dp
7 | 50dp
8 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/32.txt:
--------------------------------------------------------------------------------
1 | - Initial sync improvements
2 | - Jdenticon for user's avatar placeholders
3 | - Media usage info (only for servers that support it)
4 | - Connect with other user option
5 | - New screens for invitations
6 | - Ignored user section in Settings
7 | - More categories on People tab
8 | - Bug fixes and performance improvements
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/timeline/list/OnVideoPlayBackStateListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.timeline.list
2 |
3 | import org.futo.circles.feature.timeline.list.holder.VideoPlaybackViewHolder
4 |
5 | interface OnVideoPlayBackStateListener {
6 |
7 | fun onVideoPlaybackStateChanged(holder: VideoPlaybackViewHolder, isPlaying: Boolean)
8 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/NotifiableEvent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import java.io.Serializable
4 |
5 | sealed interface NotifiableEvent : Serializable {
6 | val eventId: String
7 | val editedEventId: String?
8 | val canBeReplaced: Boolean
9 | val isRedacted: Boolean
10 | val isUpdated: Boolean
11 | }
--------------------------------------------------------------------------------
/core/src/main/res/anim/alpha_show.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_unselected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
10 |
--------------------------------------------------------------------------------
/gallery/src/main/java/org/futo/circles/gallery/model/MediaFolderListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.gallery.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 | data class MediaFolderListItem(
6 | override val id: String,
7 | val displayName: String,
8 | val size: Long,
9 | val isSelected: Boolean = false
10 | ) : IdEntity
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/GroupListItemPayload.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | data class GroupListItemPayload(
4 | val topic: String?,
5 | val isEncrypted: Boolean?,
6 | val membersCount: Int?,
7 | val timestamp: Long?,
8 | val unreadCount: Int?,
9 | val knocksCount: Int?,
10 | val needUpdateFullItem: Boolean
11 | )
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/subscriptions/SubscriptionProvider.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.subscriptions
2 |
3 | import androidx.fragment.app.Fragment
4 |
5 | interface SubscriptionProvider {
6 |
7 | fun getManager(
8 | fragment: Fragment,
9 | itemPurchaseListener: ItemPurchasedListener?
10 | ): SubscriptionManager
11 |
12 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Circles web
4 | url: https://circles.futo.org
5 | about: You can find our contact info here.
6 | - name: Circles Matrix room
7 | url: https://matrix.to/#/!gcbIHWAYBBmvITkQIn:matrix.org?via=matrix.org&via=envs.net&via=tchncs.de
8 | about: Circle's news and discussions here.
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/SetupCirclesListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | import android.net.Uri
4 | import org.futo.circles.core.base.list.IdEntity
5 |
6 | data class SetupCirclesListItem(
7 | val name: String,
8 | val uri: Uri? = null
9 | ) : IdEntity {
10 | override val id: String
11 | get() = name
12 | }
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/SubscriptionListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 | data class SubscriptionListItem(
6 | override val id: String,
7 | val name: String,
8 | val description: String,
9 | val price: String,
10 | val duration: String
11 | ) : IdEntity
--------------------------------------------------------------------------------
/core/src/main/res/anim/slide_in.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
--------------------------------------------------------------------------------
/core/src/main/res/anim/slide_out.xml:
--------------------------------------------------------------------------------
1 |
3 |
8 |
--------------------------------------------------------------------------------
/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/markdown/mentions/plugin/MentionNode.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.markdown.mentions.plugin
2 |
3 | import org.commonmark.node.CustomNode
4 | import org.commonmark.node.Visitor
5 |
6 |
7 | class MentionNode : CustomNode() {
8 | override fun accept(visitor: Visitor) {
9 | visitor.visit(this)
10 | }
11 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/room/create/CreateRoomProgressListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.room.create
2 |
3 | enum class CreateRoomProgressStage { CreateRoom, CreateTimeline, SetParentRelations, SetTimelineRelations, Finished }
4 |
5 | interface CreateRoomProgressListener {
6 |
7 | fun onProgressUpdated(event: CreateRoomProgressStage)
8 |
9 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_unselected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
10 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/subscriptions/ItemPurchasedListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.subscriptions
2 |
3 | import org.futo.circles.auth.model.SubscriptionReceiptData
4 |
5 |
6 | interface ItemPurchasedListener {
7 |
8 | fun onItemPurchased(subscriptionReceiptData: SubscriptionReceiptData)
9 |
10 | fun onPurchaseFailed(errorCode: Int)
11 |
12 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/GroupedNotificationEvents.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.feature.notifications.ProcessedEvent
4 |
5 | data class GroupedNotificationEvents(
6 | val roomEvents: Map>>,
7 | val invitationEvents: List>
8 | )
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/provider/MatrixInstanceProvider.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.provider
2 |
3 | import org.matrix.android.sdk.api.Matrix
4 |
5 |
6 | object MatrixInstanceProvider {
7 | lateinit var matrix: Matrix
8 | private set
9 |
10 | fun saveMatrixInstance(matrixInstance: Matrix) {
11 | matrix = matrixInstance
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/timeline/post/create/PreviewPostListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.timeline.post.create
2 |
3 | import org.futo.circles.model.CreatePostContent
4 |
5 | interface PreviewPostListener {
6 | fun onUploadMediaClicked()
7 | fun onEmojiClicked()
8 | fun onAddLinkClicked()
9 | fun onSendClicked(content: CreatePostContent)
10 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/SelectRoomTypeArg.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | enum class SelectRoomTypeArg {
4 | CirclesJoined,
5 | GroupsJoined,
6 | PhotosJoined,
7 | MyCircleNotJoinedByUser
8 | }
9 |
10 | fun SelectRoomTypeArg.isCircle() =
11 | this == SelectRoomTypeArg.CirclesJoined || this == SelectRoomTypeArg.MyCircleNotJoinedByUser
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/PostItemPayload.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | import org.futo.circles.core.model.ReactionsData
4 | import org.matrix.android.sdk.api.session.room.send.SendState
5 |
6 | class PostItemPayload(
7 | val readByCount: Int,
8 | val repliesCount: Int,
9 | val reactions: List,
10 | val needToUpdateFullItem: Boolean
11 | )
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/OtherEventContent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
4 |
5 | data class OtherEventContent(
6 | val eventType: String,
7 | ) : PostContent(PostContentType.OTHER_CONTENT)
8 |
9 | fun TimelineEvent.toOtherEventContent(): OtherEventContent = OtherEventContent(root.getClearType())
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_keyboard_arrow_down.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gallery/src/main/res/transition/grid_exit_transition.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/KeepInternalDistributor.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 |
7 |
8 | class KeepInternalDistributor : BroadcastReceiver() {
9 | override fun onReceive(context: Context, intent: Intent) {}
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/circles_tab_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/credentials/CredentialsManager.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.credentials
2 |
3 | import android.content.Context
4 |
5 | interface CredentialsManager {
6 | suspend fun getPasswordCredentials(activityContext: Context, userId: String): String?
7 |
8 | suspend fun savePasswordCredentials(activityContext: Context, userId: String, password: String)
9 |
10 | }
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/ValidateUserIdStatus.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | sealed class ValidateUserIdStatus
4 |
5 | data object EmptyUserId : ValidateUserIdStatus()
6 | data object InvalidUserId : ValidateUserIdStatus()
7 | data class ValidUserId(val userId: String) : ValidateUserIdStatus()
8 | data class SuggestedUserId(val suggestedUserId: String) : ValidateUserIdStatus()
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_rich_text_menu_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/DiscoveryResponse.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class DiscoveryResponse(
6 | @SerializedName("unifiedpush") val unifiedpush: DiscoveryUnifiedPush = DiscoveryUnifiedPush()
7 | )
8 |
9 | data class DiscoveryUnifiedPush(
10 | @SerializedName("gateway") val gateway: String = ""
11 | )
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_add.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/settings/src/main/java/org/futo/circles/settings/model/ActiveSubscriptionInfo.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.settings.model
2 |
3 | data class ActiveSubscriptionInfo(
4 | val packageName: String,
5 | val productId: String,
6 | val purchaseTime: Long,
7 | val isAutoRenewing: Boolean,
8 | val name: String,
9 | val description: String,
10 | val price: String,
11 | val duration: String
12 | )
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/SwitchUserListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 | import org.matrix.android.sdk.api.session.Session
5 | import org.matrix.android.sdk.api.session.user.model.User
6 |
7 | data class SwitchUserListItem(
8 | override val id: String,
9 | val session: Session,
10 | val user: User
11 | ) : IdEntity
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/AccessLevelListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 | import org.matrix.android.sdk.api.session.room.powerlevels.Role
5 |
6 | data class AccessLevelListItem(
7 | val role: Role,
8 | val isSelected: Boolean = false
9 | ) : IdEntity {
10 | override val id: String = role.value.toString()
11 | }
--------------------------------------------------------------------------------
/core/src/main/res/layout/list_item_invite_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gallery/src/main/res/transition/image_shared_element_transition.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/timeline/post/menu/PostMenuListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.timeline.post.menu
2 |
3 | import org.futo.circles.core.model.PostContent
4 |
5 |
6 | interface PostMenuListener {
7 | fun onIgnore(senderId: String)
8 | fun onSaveToDevice(content: PostContent)
9 | fun onRemove(roomId: String, eventId: String)
10 | fun endPoll(roomId: String, eventId: String)
11 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_send.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/RoomRequestTypeArg.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | enum class RoomRequestTypeArg { Circle, Group, Photo, DM }
4 |
5 |
6 | fun RoomRequestTypeArg.toRoomTypeString() = when (this) {
7 | RoomRequestTypeArg.Circle -> TIMELINE_TYPE
8 | RoomRequestTypeArg.Group -> GROUP_TYPE
9 | RoomRequestTypeArg.Photo -> GALLERY_TYPE
10 | RoomRequestTypeArg.DM -> ""
11 | }
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_play_round.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_italic.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_error.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_reply.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/auth/src/main/res/layout/fragment_empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_error.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_resend.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_strikethrough.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_video.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
11 |
14 |
17 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/NotificationTestListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 | import org.futo.circles.core.model.TaskStatus
5 |
6 | data class NotificationTestListItem(
7 | val titleId: Int,
8 | val message: String,
9 | val status: TaskStatus,
10 | val hasFix: Boolean
11 | ) : IdEntity {
12 | override val id: Int = titleId
13 | }
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_download.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_text.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_check.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_keyboard_arrow_up.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/xml/bg_chip.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/CreatePostContent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | import android.net.Uri
4 | import org.futo.circles.core.model.MediaType
5 |
6 | sealed class CreatePostContent
7 |
8 | data class TextPostContent(
9 | val text: String
10 | ) : CreatePostContent()
11 |
12 | data class MediaPostContent(
13 | val caption: String?,
14 | val uri: Uri,
15 | val mediaType: MediaType
16 | ) : CreatePostContent()
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #80000000
5 | #4D0E7AFE
6 | #00008b
7 | #52000000
8 | #C0E6FF
9 | #D5C4FF
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/org/futo/circles/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/settings/src/main/res/drawable/ic_email.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/people_tab_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/recovery/EnterPassPhraseDialogListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.feature.pass_phrase.recovery
2 |
3 | import android.net.Uri
4 |
5 | interface EnterPassPhraseDialogListener {
6 | fun onRestoreBackupWithPassphrase(passphrase: String)
7 |
8 | fun onRestoreBackupWithRawKey(key: String)
9 | fun onRestoreBackup(uri: Uri)
10 | fun onDoNotRestore()
11 | fun onSelectFileClicked()
12 | }
--------------------------------------------------------------------------------
/auth/src/test/java/org/futo/circles/auth/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/FcmHelper.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications
2 |
3 | interface FcmHelper {
4 | fun isFirebaseAvailable(): Boolean
5 |
6 | fun getFcmToken(): String?
7 |
8 | fun storeFcmToken(token: String?)
9 |
10 | fun ensureFcmTokenIsRetrieved(pushersManager: PushersManager, registerPusher: Boolean)
11 |
12 | fun onEnterForeground()
13 |
14 | fun onEnterBackground()
15 | }
16 |
--------------------------------------------------------------------------------
/core/src/main/res/layout/fragment_pick_gallery.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/layout/list_item_invite_member.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/test/java/org/futo/circles/core/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/gallery/src/test/java/org/futo/circles/gallery/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.gallery
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/settings/src/main/res/drawable/ic_payment.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/settings/src/test/java/org/futo/circles/settings/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.settings
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PostContentType.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.matrix.android.sdk.api.session.room.model.message.MessageType
4 |
5 | enum class PostContentType(val typeKey: String) {
6 | TEXT_CONTENT(MessageType.MSGTYPE_TEXT),
7 | IMAGE_CONTENT(MessageType.MSGTYPE_IMAGE),
8 | VIDEO_CONTENT(MessageType.MSGTYPE_VIDEO),
9 | POLL_CONTENT(MessageType.MSGTYPE_POLL_START),
10 | OTHER_CONTENT("other_content")
11 | }
--------------------------------------------------------------------------------
/core/src/main/res/menu/user_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | Circles combines the ease of use and convenience of an online social network with the privacy and security of an encrypted messenger.
2 |
3 | All posts are encrypted end-to-end, and there are no ads and no tracking.
4 |
5 | Connect with the people who truly matter in your life, without creepy ad networks spying on every interaction.
6 |
7 | Safely share photos of your kids with grandparents, aunts and uncles, friends and other family members.
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.circles
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.asLiveData
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import javax.inject.Inject
7 |
8 | @HiltViewModel
9 | class CirclesViewModel @Inject constructor(
10 | dataSource: CirclesDataSource
11 | ) : ViewModel() {
12 |
13 | val roomsLiveData = dataSource.getCirclesFlow().asLiveData()
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/groups/GroupsViewModel.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.groups
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.asLiveData
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import javax.inject.Inject
7 |
8 | @HiltViewModel
9 | class GroupsViewModel @Inject constructor(
10 | dataSource: GroupsDataSource
11 | ) : ViewModel() {
12 |
13 | val roomsLiveData = dataSource.getGroupsFlow().asLiveData()
14 |
15 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/ShareUrlTypeArg.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | enum class ShareUrlTypeArg(val typeKey: String) {
4 | ROOM("room"),
5 | GALLERY("gallery"),
6 | GROUP("group"),
7 | TIMELINE("timeline")
8 | }
9 |
10 | fun shareUrlTypeArgFromType(type: String): ShareUrlTypeArg? {
11 | val urlType: ShareUrlTypeArg? = null
12 | ShareUrlTypeArg.entries.forEach { if (type == it.typeKey) return it }
13 | return urlType
14 | }
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_app_version.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_create.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/FileExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import androidx.core.content.FileProvider
6 | import org.futo.circles.core.base.FILE_PROVIDER_AUTHORITY_EXTENSION
7 | import java.io.File
8 |
9 | fun File.getUri(context: Context): Uri = FileProvider.getUriForFile(
10 | context, context.applicationContext.packageName + FILE_PROVIDER_AUTHORITY_EXTENSION, this
11 | )
--------------------------------------------------------------------------------
/core/src/main/res/values-night/color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #64B5F6
4 | #333333
5 | #ABABAB
6 | #2D2D2D
7 | @color/menu_icon_color
8 | @color/white
9 | #121212
10 |
--------------------------------------------------------------------------------
/gallery/src/main/java/org/futo/circles/gallery/feature/PhotosViewModel.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.gallery.feature
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.asLiveData
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import javax.inject.Inject
7 |
8 | @HiltViewModel
9 | class PhotosViewModel @Inject constructor(
10 | dataSource: PhotosDataSource
11 | ) : ViewModel() {
12 |
13 | val roomsLiveData = dataSource.getGalleriesFlow().asLiveData()
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/direct/tab/DMViewModel.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.direct.tab
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.asLiveData
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import javax.inject.Inject
7 |
8 | @HiltViewModel
9 | class DMViewModel @Inject constructor(
10 | dataSource: DMDataSource
11 | ) : ViewModel() {
12 |
13 | val dmsLiveData = dataSource.getDirectMessagesListFlow().asLiveData()
14 |
15 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/picker/gallery/media/list/holder/GalleryTimelineItemViewHolder.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.picker.gallery.media.list.holder
2 |
3 | import android.view.View
4 | import androidx.recyclerview.widget.RecyclerView
5 | import org.futo.circles.core.model.GalleryTimelineListItem
6 |
7 | abstract class GalleryTimelineItemViewHolder(view: View) : RecyclerView.ViewHolder(view) {
8 |
9 | abstract fun bind(item: GalleryTimelineListItem)
10 |
11 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PostContent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 |
4 | sealed class PostContent(open val type: PostContentType) {
5 | fun isMedia(): Boolean =
6 | type == PostContentType.IMAGE_CONTENT || type == PostContentType.VIDEO_CONTENT
7 |
8 | fun isPoll(): Boolean = type == PostContentType.POLL_CONTENT
9 |
10 | fun isText(): Boolean = type == PostContentType.TEXT_CONTENT
11 | }
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_close.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/layout/list_item_no_results.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_more.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/ProcessedEvent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications
2 |
3 | data class ProcessedEvent(
4 | val type: Type,
5 | val event: T
6 | ) {
7 |
8 | enum class Type {
9 | KEEP,
10 | REMOVE
11 | }
12 | }
13 |
14 | fun List>.onlyKeptEvents() = mapNotNull { processedEvent ->
15 | processedEvent.event.takeIf { processedEvent.type == ProcessedEvent.Type.KEEP }
16 | }
17 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/MediaFileData.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import android.net.Uri
4 | import org.matrix.android.sdk.api.session.crypto.attachments.ElementToDecrypt
5 |
6 | data class MediaFileData(
7 | val fileName: String,
8 | val mimeType: String,
9 | val fileUrl: String,
10 | val elementToDecrypt: ElementToDecrypt?,
11 | val width: Int,
12 | val height: Int,
13 | val duration: String,
14 | val videoUri: Uri? = null
15 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_fullscreen.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_poll.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_check_circle.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_direct_messages.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_gallery.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/gallery/src/main/res/drawable/ic_check_circle.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/ic_file.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_phone.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_phone.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/settings/src/main/res/drawable/ic_key.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_logout.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/gallery/src/main/res/drawable/ic_create.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_image.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_number_list.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/mapping/MatrixUserMapping.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.mapping
2 |
3 | import org.futo.circles.core.mapping.toCirclesUserSummary
4 | import org.futo.circles.model.PeopleIgnoredUserListItem
5 | import org.futo.circles.model.PeopleUserListItem
6 | import org.matrix.android.sdk.api.session.user.model.User
7 |
8 |
9 | fun User.toPeopleUserListItem(isIgnored: Boolean) = PeopleUserListItem(toCirclesUserSummary(), isIgnored)
10 |
11 | fun User.toPeopleIgnoredListItem() = PeopleIgnoredUserListItem(toCirclesUserSummary())
12 |
13 |
14 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_invite.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_filter.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/core/src/main/res/layout/view_spinner_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/textDrawable/ColorGenerator.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.textDrawable
2 |
3 | import kotlin.math.abs
4 |
5 | class ColorGenerator {
6 |
7 | private val colors = mutableListOf(
8 | -0xe9c9c,
9 | -0xa7aa7,
10 | -0x65bc2,
11 | -0x1b39d2,
12 | -0x98408c,
13 | -0xa65d42,
14 | -0xdf6c33,
15 | -0x529d59,
16 | -0x7fa87f
17 | )
18 |
19 | fun getColor(key: Any): Int {
20 | return colors[abs(key.hashCode()) % colors.size]
21 | }
22 | }
--------------------------------------------------------------------------------
/core/src/main/res/layout/list_item_timeline_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/auth/src/main/res/drawable/ic_lightbulb.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/test/task/TestNotificationReceiver.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications.test.task
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import androidx.localbroadcastmanager.content.LocalBroadcastManager
7 |
8 | class TestNotificationReceiver : BroadcastReceiver() {
9 |
10 | override fun onReceive(context: Context, intent: Intent) {
11 | LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/room/manage_members/ManageMembersOptionsListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.room.manage_members
2 |
3 | import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
4 |
5 | interface ManageMembersOptionsListener {
6 | fun onSetAccessLevel(userId: String, powerLevelsContent: PowerLevelsContent)
7 | fun onRemoveUser(userId: String)
8 | fun onBanUser(userId: String)
9 | fun unBanUser(userId: String)
10 | fun cancelPendingInvitation(userId: String)
11 | fun resendInvitation(userId: String)
12 | }
--------------------------------------------------------------------------------
/gallery/src/main/res/drawable/ic_backup.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/NotificationActionIds.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications
2 |
3 | import org.futo.circles.core.base.CirclesAppConfig
4 |
5 | object NotificationActionIds {
6 |
7 | val markRoomRead = "${CirclesAppConfig.appId}.NotificationActions.MARK_ROOM_READ_ACTION"
8 | val dismissRoom =
9 | "${CirclesAppConfig.appId}.NotificationActions.DISMISS_ROOM_NOTIF_ACTION"
10 | val diagnostic = "${CirclesAppConfig.appId}.NotificationActions.DIAGNOSTIC"
11 | val push = "${CirclesAppConfig.appId}.PUSH"
12 |
13 | }
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_notifications.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_report.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_winner.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_emiji_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/core/src/main/res/layout/list_item_chip.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
--------------------------------------------------------------------------------
/settings/src/main/res/drawable/ic_verified.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/GalleryContentListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 |
5 | sealed class GalleryTimelineListItem : IdEntity
6 |
7 | data class GalleryContentListItem(
8 | override val id: String,
9 | val postInfo: PostInfo,
10 | val mediaContent: MediaContent,
11 | val isSelected: Boolean = false
12 | ) : GalleryTimelineListItem()
13 |
14 | data class GalleryTimelineLoadingListItem(
15 | override val id: String = "GalleryTimelineLoadingListItem"
16 | ) : GalleryTimelineListItem()
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/timeline/data_source/ReadMessageDataSource.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.timeline.data_source
2 |
3 | import org.futo.circles.core.provider.MatrixSessionProvider
4 | import org.matrix.android.sdk.api.session.room.read.ReadService
5 | import javax.inject.Inject
6 |
7 | class ReadMessageDataSource @Inject constructor() {
8 |
9 | suspend fun markRoomAsRead(roomId: String) {
10 | MatrixSessionProvider.currentSession?.roomService()?.getRoom(roomId)?.readService()
11 | ?.markAsRead(ReadService.MarkAsReadParams.BOTH, false)
12 | }
13 | }
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/bsspeke/BSSpekeClientProvider.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.bsspeke
2 |
3 | object BSSpekeClientProvider {
4 |
5 | private var clientInstance: BSSpekeClient? = null
6 |
7 | fun getClientOrThrow() =
8 | clientInstance ?: throw IllegalArgumentException("BsSpeke client is not initialized")
9 |
10 | fun initClient(userPart: String, domain: String, password: String) {
11 | clientInstance = BSSpekeClient("@$userPart:$domain", domain, password)
12 | }
13 |
14 | fun clear() {
15 | clientInstance = null
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/NavControllerExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import android.net.Uri
4 | import androidx.annotation.IdRes
5 | import androidx.navigation.NavController
6 | import androidx.navigation.NavDirections
7 | import org.matrix.android.sdk.api.extensions.tryOrNull
8 |
9 | fun NavController.navigateSafe(directions: NavDirections) = tryOrNull { navigate(directions) }
10 | fun NavController.navigateSafe(@IdRes resId: Int) = tryOrNull { navigate(resId) }
11 | fun NavController.navigateSafe(deepLink: Uri) = tryOrNull { navigate(deepLink) }
12 |
--------------------------------------------------------------------------------
/app/src/gplay/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/AccessLevel.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.READ_ONLY_ROLE
4 | import org.matrix.android.sdk.api.session.room.powerlevels.Role
5 |
6 | enum class AccessLevel(val levelValue: Int) {
7 | Admin(Role.Admin.value),
8 | Moderator(Role.Moderator.value),
9 | User(Role.Default.value),
10 | ReadOnly(READ_ONLY_ROLE);
11 |
12 | companion object {
13 | fun fromValue(value: Int): AccessLevel =
14 | AccessLevel.entries.firstOrNull { it.levelValue == value } ?: User
15 | }
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_lock.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/subscriptions/SubscriptionManager.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.subscriptions
2 |
3 | import org.futo.circles.auth.model.SubscriptionListItem
4 | import org.futo.circles.auth.model.SubscriptionReceiptData
5 | import org.futo.circles.core.extensions.Response
6 |
7 | interface SubscriptionManager {
8 |
9 | suspend fun getActiveSubscriptionReceipt(): Response
10 |
11 | suspend fun getDetails(productIds: List): Response>
12 |
13 | suspend fun purchaseProduct(productId: String): Response
14 |
15 | }
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_seen.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/gallery/src/main/res/layout/fragment_select_galleries.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/gallery/src/main/res/menu/gallery_image_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_delete.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_lock_open.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/DMListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 | import org.futo.circles.core.model.CirclesUserSummary
5 |
6 | sealed class DMListItem(
7 | override val id: String
8 | ) : IdEntity
9 |
10 | data class JoinedDMsListItem(
11 | override val id: String,
12 | val user: CirclesUserSummary,
13 | val timestamp: Long,
14 | val unreadCount: Int
15 | ) : DMListItem(id)
16 |
17 | data class DMsInvitesNotificationListItem(
18 | val invitesCount: Int
19 | ) : DMListItem("DirectMessagesInvitesNotificationListItem")
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bold.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_knock_requests.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_switch_user.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_deactivate_account.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_edit.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_reload.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/menu/timeline_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/picker/GetContentWithMultiFilter.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.picker
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import androidx.activity.result.contract.ActivityResultContracts
6 |
7 | class GetContentWithMultiFilter : ActivityResultContracts.GetContent() {
8 | override fun createIntent(context: Context, input: String): Intent {
9 | val inputArray = input.split(";").toTypedArray()
10 | val myIntent = super.createIntent(context, "*/*")
11 | myIntent.putExtra(Intent.EXTRA_MIME_TYPES, inputArray)
12 | return myIntent
13 | }
14 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/mapping/MatrixUserMapping.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.mapping
2 |
3 | import org.futo.circles.core.extensions.notEmptyDisplayName
4 | import org.futo.circles.core.model.CirclesUserSummary
5 | import org.futo.circles.core.model.UserListItem
6 | import org.matrix.android.sdk.api.session.user.model.User
7 |
8 | fun User.toUserListItem(isSelected: Boolean) = UserListItem(
9 | user = toCirclesUserSummary(),
10 | isSelected = isSelected
11 | )
12 |
13 | fun User.toCirclesUserSummary() = CirclesUserSummary(
14 | id = userId,
15 | name = notEmptyDisplayName(),
16 | avatarUrl = avatarUrl ?: ""
17 | )
--------------------------------------------------------------------------------
/gallery/src/main/java/org/futo/circles/gallery/model/MediaToBackupItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.gallery.model
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import org.futo.circles.core.extensions.getUri
6 | import org.futo.circles.core.base.list.IdEntity
7 | import java.io.File
8 |
9 | data class MediaToBackupItem(
10 | val displayName: String,
11 | val uri: Uri,
12 | val size: Long,
13 | val dateModified: Long
14 | ) : IdEntity {
15 | override val id: Uri = uri
16 | }
17 |
18 | fun File.toMediaToBackupItem(context: Context) = MediaToBackupItem(
19 | name, getUri(context), length(), lastModified()
20 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_photo.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_circles_explanation.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/InviteNotifiableEvent.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | data class InviteNotifiableEvent(
4 | val matrixID: String?,
5 | override val eventId: String,
6 | override val editedEventId: String?,
7 | override val canBeReplaced: Boolean,
8 | val roomId: String,
9 | val roomName: String?,
10 | val noisy: Boolean,
11 | val title: String,
12 | val description: String,
13 | val type: String?,
14 | val timestamp: Long,
15 | val soundName: String?,
16 | override val isRedacted: Boolean = false,
17 | override val isUpdated: Boolean = false
18 | ) : NotifiableEvent
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/PostInfo.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.provider.MatrixSessionProvider
4 | import org.matrix.android.sdk.api.session.room.sender.SenderInfo
5 |
6 | data class PostInfo(
7 | val id: String,
8 | val roomId: String,
9 | val sender: SenderInfo,
10 | val isEncrypted: Boolean,
11 | val timestamp: Long,
12 | val isEdited: Boolean,
13 | val editTimestamp: Long?
14 | ) {
15 | fun isMyPost(): Boolean =
16 | sender.userId == MatrixSessionProvider.currentSession?.myUserId
17 |
18 | fun getLastModifiedTimestamp() = editTimestamp ?: timestamp
19 | }
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_add_photo.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/modules_release_clean.sh:
--------------------------------------------------------------------------------
1 |
2 | # Remove .aar and pom.xml from the root directory if they exist
3 | rm -f auth-gplay-release.aar
4 | rm -f auth-fdroid-release.aar
5 |
6 | rm -f core-gplay-release.aar
7 | rm -f core-fdroid-release.aar
8 |
9 | rm -f gallery-gplay-release.aar
10 | rm -f gallery-fdroid-release.aar
11 |
12 | rm -f settings-gplay-release.aar
13 | rm -f settings-fdroid-release.aar
14 |
15 | rm -f pom_auth_gplay.xml
16 | rm -f pom_auth_fdroid.xml
17 |
18 | rm -f pom_core_gplay.xml
19 | rm -f pom_core_fdroid.xml
20 |
21 | rm -f pom_gallery_gplay.xml
22 | rm -f pom_gallery_fdroid.xml
23 |
24 | rm -f pom_settings_gplay.xml
25 | rm -f pom_settings_fdroid.xml
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/CircleRoomTypeArg.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | enum class CircleRoomTypeArg { Circle, Group, Photo }
4 |
5 | fun CircleRoomTypeArg.toShareUrlType() = when (this) {
6 | CircleRoomTypeArg.Circle -> ShareUrlTypeArg.TIMELINE
7 | CircleRoomTypeArg.Group -> ShareUrlTypeArg.GROUP
8 | CircleRoomTypeArg.Photo -> ShareUrlTypeArg.GALLERY
9 | }
10 |
11 | fun CircleRoomTypeArg.toRoomRequestArgument() = when (this) {
12 | CircleRoomTypeArg.Circle -> RoomRequestTypeArg.Circle
13 | CircleRoomTypeArg.Group -> RoomRequestTypeArg.Group
14 | CircleRoomTypeArg.Photo -> RoomRequestTypeArg.Photo
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_report_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
--------------------------------------------------------------------------------
/settings/src/main/res/layout/activity_qr_scanner.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/utils/HomeServerUtils.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.utils
2 |
3 | import android.net.Uri
4 | import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
5 |
6 | object HomeServerUtils {
7 |
8 | fun buildHomeServerConfigFromUserId(userId: String): HomeServerConnectionConfig {
9 | val domain = UserIdUtils.getServerDomain(userId)
10 | return buildHomeServerConfigFromDomain(domain)
11 | }
12 |
13 |
14 | fun buildHomeServerConfigFromDomain(domain: String) = HomeServerConnectionConfig
15 | .Builder()
16 | .withHomeServerUri(Uri.parse("https://$domain"))
17 | .build()
18 |
19 | }
--------------------------------------------------------------------------------
/app/src/main/res/navigation/nav_graph_bottom_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/core/src/fdroid/java/org/futo/circles/core/di/AppUpdateModule.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.di
2 |
3 | import dagger.Module
4 | import dagger.Provides
5 | import dagger.hilt.InstallIn
6 | import dagger.hilt.components.SingletonComponent
7 | import org.futo.circles.core.update.AppUpdateProvider
8 | import org.futo.circles.core.update.CirclesAppUpdateManager
9 |
10 | @Module
11 | @InstallIn(SingletonComponent::class)
12 | object AppUpdateModule {
13 |
14 | @Provides
15 | fun provideAppUpdateProvider(): AppUpdateProvider {
16 | return object : AppUpdateProvider {
17 | override fun getManager(): CirclesAppUpdateManager? = null
18 | }
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/RoomSummaryExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import org.futo.circles.core.mapping.nameOrId
4 | import org.futo.circles.core.model.RoomInfo
5 | import org.futo.circles.core.utils.getTimelineRoomFor
6 | import org.matrix.android.sdk.api.session.room.model.RoomSummary
7 |
8 | fun RoomSummary.toRoomInfo(isCircle: Boolean): RoomInfo =
9 | if (isCircle) {
10 | val timeline = getTimelineRoomFor(roomId)?.roomSummary()
11 | RoomInfo(timeline?.nameOrId() ?: nameOrId(),
12 | timeline?.avatarUrl?.takeIf { it.isNotEmpty() } ?: avatarUrl
13 | )
14 | } else RoomInfo(nameOrId(), avatarUrl)
--------------------------------------------------------------------------------
/app/src/fdroid/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bullet_list.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_help.xml:
--------------------------------------------------------------------------------
1 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/auth/src/fdroid/java/org/futo/circles/auth/di/CredentialsModule.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.di
2 |
3 | import dagger.Module
4 | import dagger.Provides
5 | import dagger.hilt.InstallIn
6 | import dagger.hilt.components.SingletonComponent
7 | import org.futo.circles.auth.credentials.CredentialsManager
8 | import org.futo.circles.auth.credentials.CredentialsProvider
9 |
10 | @Module
11 | @InstallIn(SingletonComponent::class)
12 | object CredentialsModule {
13 |
14 | @Provides
15 | fun provideCredentialsProvider(): CredentialsProvider {
16 | return object : CredentialsProvider {
17 | override fun getManager(): CredentialsManager? = null
18 | }
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_curved_arrow.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_ignore.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_unfollow.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_photo.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/direct/timeline/listeners/DmOptionsListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.direct.timeline.listeners
2 |
3 | import org.futo.circles.core.model.PostContent
4 |
5 | interface DmOptionsListener {
6 |
7 | fun onShowMenuClicked(eventId: String)
8 | fun onShare(content: PostContent)
9 | fun onReply(message: String)
10 | fun onShowPreview(eventId: String)
11 | fun onShowEmoji(eventId: String, onAddEmoji: (String) -> Unit)
12 | fun onEmojiChipClicked(eventId: String, emoji: String, isUnSend: Boolean)
13 | fun onSaveToDevice(content: PostContent)
14 | fun onRemove(eventId: String)
15 | fun onEditActionClicked(eventId: String, message: String)
16 |
17 | }
--------------------------------------------------------------------------------
/settings/src/main/res/drawable/ic_round_photo_library.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_round_contacts.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/SecretKeyData.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | import org.matrix.android.sdk.api.session.crypto.keysbackup.BackupRecoveryKey
4 | import org.matrix.android.sdk.api.session.crypto.keysbackup.computeRecoveryKey
5 | import org.matrix.android.sdk.api.session.securestorage.SsssKeySpec
6 | import org.matrix.android.sdk.api.util.fromBase64
7 |
8 | data class SecretKeyData(
9 | val keyId: String,
10 | val secretBase64: String,
11 | val keySpec: SsssKeySpec
12 | ) {
13 | fun getBackupRecoveryKey(): BackupRecoveryKey {
14 | val recoveryBase58 = computeRecoveryKey(secretBase64.fromBase64())
15 | return BackupRecoveryKey.fromBase58(recoveryBase58)
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/base/ExpandableItemsDataSource.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.base
2 |
3 | import kotlinx.coroutines.flow.MutableStateFlow
4 | import kotlinx.coroutines.flow.update
5 |
6 | interface ExpandableItemsDataSource {
7 |
8 | val itemsWithVisibleOptionsFlow: MutableStateFlow>
9 |
10 | fun toggleOptionsVisibilityFor(id: String) {
11 | val isOptionsVisible = itemsWithVisibleOptionsFlow.value.contains(id)
12 | itemsWithVisibleOptionsFlow.update { value ->
13 | val newSet = mutableSetOf().apply { addAll(value) }
14 | if (isOptionsVisible) newSet.remove(id)
15 | else newSet.add(id)
16 | newSet
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/notifications/CircularCache.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.notifications
2 |
3 | class CircularCache(cacheSize: Int, factory: (Int) -> Array) {
4 |
5 | companion object {
6 | inline fun create(cacheSize: Int) =
7 | CircularCache(cacheSize) { Array(cacheSize) { null } }
8 | }
9 |
10 | private val cache = factory(cacheSize)
11 | private var writeIndex = 0
12 |
13 | fun contains(value: T): Boolean = cache.contains(value)
14 |
15 | fun put(value: T) {
16 | if (writeIndex == cache.size) {
17 | writeIndex = 0
18 | }
19 | cache[writeIndex] = value
20 | writeIndex++
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_emoji.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/gplay/java/org/futo/circles/core/di/AppUpdateModule.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.di
2 |
3 | import dagger.Module
4 | import dagger.Provides
5 | import dagger.hilt.InstallIn
6 | import dagger.hilt.components.SingletonComponent
7 | import org.futo.circles.core.update.CirclesAppUpdateManager
8 | import org.futo.circles.core.update.AppUpdateProvider
9 | import org.futo.circles.core.update.GoogleAppUpdateManager
10 |
11 | @Module
12 | @InstallIn(SingletonComponent::class)
13 | object AppUpdateModule {
14 |
15 | @Provides
16 | fun provideAppUpdateProvider(): AppUpdateProvider {
17 | return object : AppUpdateProvider {
18 | override fun getManager(): CirclesAppUpdateManager = GoogleAppUpdateManager()
19 | }
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/gallery/src/main/java/org/futo/circles/gallery/feature/select/SelectGalleriesViewModel.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.gallery.feature.select
2 |
3 | import androidx.lifecycle.ViewModel
4 | import dagger.hilt.android.lifecycle.HiltViewModel
5 | import org.futo.circles.core.model.SelectableRoomListItem
6 | import javax.inject.Inject
7 |
8 | @HiltViewModel
9 | class SelectGalleriesViewModel @Inject constructor(
10 | private val selectGalleriesDataSource: SelectGalleriesDataSource
11 | ) : ViewModel() {
12 |
13 | val galleriesLiveData = selectGalleriesDataSource.galleriesLiveData
14 |
15 | fun toggleGallerySelect(selectableRoomListItem: SelectableRoomListItem) {
16 | selectGalleriesDataSource.toggleGallerySelect(selectableRoomListItem)
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/room/select/SelectRoomsViewModel.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.room.select
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.asLiveData
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import org.futo.circles.core.model.SelectableRoomListItem
7 | import javax.inject.Inject
8 |
9 | @HiltViewModel
10 | class SelectRoomsViewModel @Inject constructor(
11 | private val dataSource: SelectRoomsDataSource
12 | ) : ViewModel() {
13 |
14 | val roomsLiveData = dataSource.roomsFlow.asLiveData()
15 |
16 | fun getSelectedRooms() = dataSource.getSelectedRooms()
17 |
18 | fun onRoomSelected(item: SelectableRoomListItem) {
19 | dataSource.toggleRoomSelect(item)
20 | }
21 | }
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_mention.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | @file:Suppress("UnstableApiUsage")
2 |
3 | import org.gradle.api.initialization.resolve.RepositoriesMode.FAIL_ON_PROJECT_REPOS
4 |
5 | pluginManagement {
6 | repositories {
7 | google()
8 | gradlePluginPortal()
9 | mavenCentral()
10 | mavenLocal()
11 | maven { url = uri("https://jitpack.io") }
12 |
13 | }
14 | }
15 | dependencyResolutionManagement {
16 | repositoriesMode.set(FAIL_ON_PROJECT_REPOS)
17 | repositories {
18 | google()
19 | mavenCentral()
20 | mavenLocal()
21 | maven { url = uri("https://jitpack.io") }
22 | }
23 | }
24 |
25 | include(":app")
26 | include(":auth")
27 | include(":core")
28 | include(":gallery")
29 | include(":settings")
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/GroupListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 | import org.futo.circles.core.model.RoomInfo
5 |
6 | sealed class GroupListItem(
7 | override val id: String
8 | ) : IdEntity
9 |
10 | data class JoinedGroupListItem(
11 | override val id: String,
12 | val info: RoomInfo,
13 | val topic: String,
14 | val membersCount: Int,
15 | val knockRequestsCount: Int,
16 | val isEncrypted: Boolean,
17 | val timestamp: Long,
18 | val unreadCount: Int
19 | ) : GroupListItem(id)
20 |
21 | data class GroupInvitesNotificationListItem(
22 | val invitesCount: Int,
23 | val knockRequestsCount: Int
24 | ) : GroupListItem("GroupInvitesNotificationListItem")
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_people_search_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/utils/UserIdUtils.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.utils
2 |
3 | import org.futo.circles.core.provider.MatrixSessionProvider
4 |
5 |
6 | object UserIdUtils {
7 |
8 | fun removeDomainSuffix(userId: String): String {
9 | val serverDomain = MatrixSessionProvider.currentSession?.sessionParams?.homeServerHost ?: ""
10 | val shortUserId: String = if (userId.endsWith(":$serverDomain"))
11 | userId.removeSuffix(":$serverDomain")
12 | else {
13 | val shortDomain = serverDomain.substringAfter("matrix.")
14 | userId.removeSuffix(":$shortDomain")
15 | }
16 | return shortUserId
17 | }
18 |
19 | fun getServerDomain(userId: String) = userId.substringAfter(":")
20 |
21 | }
--------------------------------------------------------------------------------
/gallery/src/main/java/org/futo/circles/gallery/feature/share/UploadToGalleryActivity.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.gallery.feature.share
2 |
3 | import dagger.hilt.android.AndroidEntryPoint
4 | import org.futo.circles.core.feature.room.select.interfaces.RoomsPicker
5 | import org.futo.circles.core.feature.share.BaseShareActivity
6 | import org.futo.circles.gallery.R
7 | import org.futo.circles.gallery.feature.select.SelectGalleriesFragment
8 |
9 | @AndroidEntryPoint
10 | class UploadToGalleryActivity : BaseShareActivity() {
11 |
12 | override val titleResId: Int = R.string.upload_to_gallery
13 | override val roomsPicker: RoomsPicker = SelectGalleriesFragment()
14 |
15 | override fun getShareRoomsIds(): List = roomsPicker.getSelectedRooms().map { it.id }
16 |
17 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/picker/gallery/rooms/PickGalleryViewModel.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.picker.gallery.rooms
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.map
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import org.futo.circles.core.mapping.toJoinedGalleryListItem
7 | import org.futo.circles.core.utils.getGalleriesLiveData
8 | import org.matrix.android.sdk.api.session.room.model.Membership
9 | import javax.inject.Inject
10 |
11 | @HiltViewModel
12 | class PickGalleryViewModel @Inject constructor() : ViewModel() {
13 |
14 | val galleriesLiveData = getGalleriesLiveData(membershipFilter = listOf(Membership.JOIN))
15 | .map { galleries -> galleries.map { it.toJoinedGalleryListItem() } }
16 |
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/timeline/list/PostOptionsListener.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.timeline.list
2 |
3 | import android.view.View
4 | import org.futo.circles.core.model.PostContent
5 |
6 |
7 | interface PostOptionsListener {
8 | fun onShowMenuClicked(roomId: String, eventId: String)
9 | fun onUserClicked(userId: String)
10 | fun onShare(content: PostContent, view: View)
11 | fun onReply(roomId: String, eventId: String)
12 | fun onShowPreview(roomId: String, eventId: String)
13 | fun onShowEmoji(roomId: String, eventId: String, onAddEmoji: (String) -> Unit)
14 | fun onEmojiChipClicked(roomId: String, eventId: String, emoji: String, isUnSend: Boolean)
15 | fun onPollOptionSelected(roomId: String, eventId: String, optionId: String)
16 | }
--------------------------------------------------------------------------------
/auth/src/gplay/java/org/futo/circles/auth/di/CredentialsModule.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.di
2 |
3 | import dagger.Module
4 | import dagger.Provides
5 | import dagger.hilt.InstallIn
6 | import dagger.hilt.components.SingletonComponent
7 | import org.futo.circles.auth.credentials.CredentialsManager
8 | import org.futo.circles.auth.credentials.CredentialsProvider
9 | import org.futo.circles.auth.credentials.GoogleCredentialsManager
10 |
11 | @Module
12 | @InstallIn(SingletonComponent::class)
13 | object CredentialsModule {
14 |
15 | @Provides
16 | fun provideCredentialsProvider(): CredentialsProvider {
17 | return object : CredentialsProvider {
18 | override fun getManager(): CredentialsManager = GoogleCredentialsManager()
19 | }
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/settings/src/main/res/drawable/ic_unverified.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/Post.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 | import org.matrix.android.sdk.api.session.room.send.SendState
5 |
6 | sealed class PostListItem : IdEntity
7 | data class TimelineLoadingItem(
8 | override val id: String = "TimelineLoadingItem"
9 | ) : PostListItem()
10 |
11 | data class Post(
12 | val postInfo: PostInfo,
13 | val content: PostContent,
14 | val readByCount: Int,
15 | val repliesCount: Int,
16 | val reactionsData: List,
17 | val timelineName: String? = null,
18 | val timelineOwnerName: String? = null
19 | ) : PostListItem() {
20 | override val id: String get() = postInfo.id
21 | fun isMyPost(): Boolean = postInfo.isMyPost()
22 | }
--------------------------------------------------------------------------------
/core/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/NotificationAction.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.matrix.android.sdk.api.session.pushrules.Action
4 |
5 | data class NotificationAction(
6 | val shouldNotify: Boolean,
7 | val highlight: Boolean,
8 | val soundName: String?
9 | )
10 |
11 | fun List.toNotificationAction(): NotificationAction {
12 | var shouldNotify = false
13 | var highlight = false
14 | var sound: String? = null
15 | forEach { action ->
16 | when (action) {
17 | is Action.Notify -> shouldNotify = true
18 | is Action.Highlight -> highlight = action.highlight
19 | is Action.Sound -> sound = action.sound
20 | }
21 | }
22 | return NotificationAction(shouldNotify, highlight, sound)
23 | }
24 |
--------------------------------------------------------------------------------
/core/src/main/res/layout/dialog_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/user/UserOptionsDataSource.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.user
2 |
3 | import org.futo.circles.core.extensions.createResult
4 | import org.futo.circles.core.provider.MatrixSessionProvider
5 | import javax.inject.Inject
6 |
7 | class UserOptionsDataSource @Inject constructor() {
8 |
9 | val ignoredUsersLiveData =
10 | MatrixSessionProvider.currentSession?.userService()?.getIgnoredUsersLive()
11 |
12 | suspend fun ignoreSender(userId: String) = createResult {
13 | MatrixSessionProvider.currentSession?.userService()?.ignoreUserIds(listOf(userId))
14 | }
15 |
16 | suspend fun unIgnoreSender(userId: String) = createResult {
17 | MatrixSessionProvider.currentSession?.userService()?.unIgnoreUserIds(listOf(userId))
18 | }
19 |
20 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/ResLoadingData.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import androidx.annotation.StringRes
4 | import org.futo.circles.core.R
5 |
6 | sealed class LoadingData(
7 | open var progress: Int,
8 | open var total: Int,
9 | open var isLoading: Boolean
10 | )
11 |
12 | data class ResLoadingData(
13 | @StringRes var messageId: Int = R.string.loading,
14 | override var progress: Int = 0,
15 | override var total: Int = 0,
16 | override var isLoading: Boolean = true
17 | ) : LoadingData(progress, total, isLoading)
18 |
19 | data class MessageLoadingData(
20 | var message: String,
21 | override var progress: Int = 0,
22 | override var total: Int = 0,
23 | override var isLoading: Boolean = true
24 | ) : LoadingData(progress, total, isLoading)
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/ViewModelExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import kotlinx.coroutines.*
6 | import kotlin.coroutines.CoroutineContext
7 |
8 | private val mainContext: CoroutineContext = Dispatchers.Main
9 | private val ioContext: CoroutineContext = Dispatchers.IO
10 |
11 | fun ViewModel.launchUi(
12 | block: suspend CoroutineScope.() -> Unit
13 | ): Job = viewModelScope.launch(mainContext + defaultExceptionHandler()) { this.block() }
14 |
15 | fun ViewModel.launchBg(
16 | exceptionHandler: CoroutineExceptionHandler = defaultExceptionHandler(),
17 | block: suspend CoroutineScope.() -> Unit
18 | ): Job = viewModelScope.launch(ioContext + exceptionHandler) { this.block() }
19 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_notifications_off.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/navigation/filter_timelines_nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/auth/src/androidTest/java/org/futo/circles/auth/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("org.futo.circles.auth.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/ConfirmationType.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | import org.futo.circles.auth.R
4 | import org.futo.circles.core.model.ConfirmationType
5 |
6 | data class RemoveUser(
7 | override val titleRes: Int = org.futo.circles.core.R.string.remove_user,
8 | override val messageRes: Int = org.futo.circles.core.R.string.remove_user_message,
9 | override val positiveButtonRes: Int = org.futo.circles.core.R.string.remove
10 | ) : ConfirmationType(titleRes, messageRes, positiveButtonRes)
11 |
12 | data class ForgotPassword(
13 | override val titleRes: Int = R.string.forgot_password,
14 | override val messageRes: Int = R.string.forgot_password_message,
15 | override val positiveButtonRes: Int = R.string.confirm
16 | ) : ConfirmationType(titleRes, messageRes, positiveButtonRes)
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/model/CustomUIAuth.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.model
2 |
3 | import org.futo.circles.auth.feature.uia.UIADataSource.Companion.USER_PARAM_KEY
4 | import org.futo.circles.core.provider.MatrixSessionProvider
5 | import org.matrix.android.sdk.api.auth.UIABaseAuth
6 | import org.matrix.android.sdk.api.util.JsonDict
7 |
8 | data class CustomUIAuth(
9 | override val session: String,
10 | val auth: JsonDict
11 | ) : UIABaseAuth {
12 | override fun hasAuthInfo() = true
13 |
14 | override fun copyWithSession(session: String) = this.copy(session = session)
15 |
16 | override fun asMap(): Map = auth.toMutableMap().apply {
17 | this["session"] = session
18 | this[USER_PARAM_KEY] = MatrixSessionProvider.currentSession?.myUserId ?: ""
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/androidTest/java/org/futo/circles/core/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("org.futo.circles.core.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/markdown/span/MentionSpan.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.markdown.span
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.text.style.DynamicDrawableSpan
6 | import androidx.core.content.ContextCompat
7 | import com.google.android.material.chip.ChipDrawable
8 | import org.futo.circles.core.R
9 |
10 | class MentionSpan(
11 | private val context: Context,
12 | val name: String
13 | ) : DynamicDrawableSpan() {
14 |
15 | override fun getDrawable(): Drawable =
16 | ChipDrawable.createFromResource(context, R.xml.bg_chip).apply {
17 | setTextColor(ContextCompat.getColor(context, R.color.blue))
18 | text = name
19 | setBounds(0, 0, intrinsicWidth, intrinsicHeight)
20 | }
21 | }
--------------------------------------------------------------------------------
/core/src/main/res/navigation/create_room_nav_graph.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/timeline/list/holder/TimelineLoadingViewHolder.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.timeline.list.holder
2 |
3 | import android.view.ViewGroup
4 | import org.futo.circles.core.base.list.ViewBindingHolder
5 | import org.futo.circles.core.databinding.ListItemTimelineLoadingBinding
6 | import org.futo.circles.core.model.PostListItem
7 | import org.futo.circles.core.model.TimelineLoadingItem
8 | import org.futo.circles.feature.timeline.base.TimelineListItemViewHolder
9 |
10 | class TimelineLoadingViewHolder(
11 | parent: ViewGroup,
12 | ) : TimelineListItemViewHolder(inflate(parent, ListItemTimelineLoadingBinding::inflate)) {
13 |
14 | private companion object : ViewBindingHolder
15 |
16 | override fun bind(item: PostListItem) {
17 | if (item !is TimelineLoadingItem) return
18 | }
19 | }
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/feature/uia/UIADataSourceProvider.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.feature.uia
2 |
3 | import org.futo.circles.auth.model.UIAFlowType
4 |
5 |
6 | object UIADataSourceProvider {
7 |
8 | private var activeFlowDataSource: UIADataSource? = null
9 |
10 | var activeFlowType: UIAFlowType? = null
11 | private set
12 |
13 | fun getDataSourceOrThrow() =
14 | activeFlowDataSource ?: throw IllegalArgumentException("Flow is not active")
15 |
16 |
17 | fun create(flowType: UIAFlowType, factory: UIADataSource.Factory): UIADataSource {
18 | activeFlowType = flowType
19 | return factory.create(flowType).also { activeFlowDataSource = it }
20 | }
21 |
22 | fun clear() {
23 | activeFlowType = null
24 | activeFlowDataSource = null
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/subscriptions/IsoPeriod.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.subscriptions
2 |
3 | import android.content.Context
4 | import org.futo.circles.auth.R
5 |
6 | fun String.formatIsoPeriod(context: Context): String = toDurationNumberPairs()
7 | .joinToString(separator = " ") { (number, duration) ->
8 | context.resources.getQuantityString(
9 | when (duration) {
10 | "D" -> R.plurals.days
11 | "W" -> R.plurals.weeks
12 | "M" -> R.plurals.months
13 | "Y" -> R.plurals.years
14 |
15 | else -> R.plurals.days
16 | }, number, number
17 | )
18 | }
19 |
20 | private fun String.toDurationNumberPairs() = removePrefix("P")
21 | .chunked(2)
22 | .map { it[0].toString().toInt() to it[1].toString() }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/model/FilterTimelinesListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 | import org.futo.circles.core.extensions.getRoomOwner
5 | import org.futo.circles.core.mapping.nameOrId
6 | import org.matrix.android.sdk.api.session.room.model.RoomSummary
7 |
8 | data class FilterTimelinesListItem(
9 | override val id: String,
10 | val name: String,
11 | val ownerName: String,
12 | val avatarUrl: String,
13 | val isSelected: Boolean
14 | ) : IdEntity
15 |
16 | fun RoomSummary.toFilterTimelinesListItem(isSelected: Boolean = true) = FilterTimelinesListItem(
17 | id = roomId,
18 | name = nameOrId(),
19 | ownerName = getRoomOwner(roomId)?.displayName ?: "",
20 | avatarUrl = avatarUrl,
21 | isSelected = isSelected
22 | )
--------------------------------------------------------------------------------
/auth/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/core/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/auth/src/main/java/org/futo/circles/auth/feature/pass_phrase/EncryptionAlgorithmHelper.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.auth.feature.pass_phrase
2 |
3 | import org.futo.circles.core.provider.MatrixSessionProvider
4 | import org.matrix.android.sdk.api.crypto.BSSPEKE_ALGORITHM_BACKUP
5 | import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult
6 | import javax.inject.Inject
7 |
8 | class EncryptionAlgorithmHelper @Inject constructor() {
9 |
10 | fun isBsSpekePassPhrase(): Boolean {
11 | val keyInfoResult = MatrixSessionProvider.getSessionOrThrow()
12 | .sharedSecretStorageService().getDefaultKey()
13 | if (!keyInfoResult.isSuccess()) return false
14 | val algo = (keyInfoResult as KeyInfoResult.Success).keyInfo.content.passphrase?.algorithm
15 | return algo == BSSPEKE_ALGORITHM_BACKUP
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/gallery/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/settings/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/settings/src/androidTest/java/org/futo/circles/settings/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.settings
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("org.futo.circles.settings.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/share/group/ShareWithGroupActivity.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.share.group
2 |
3 | import dagger.hilt.android.AndroidEntryPoint
4 | import org.futo.circles.R
5 | import org.futo.circles.core.feature.room.select.SelectRoomsFragment
6 | import org.futo.circles.core.feature.room.select.interfaces.RoomsPicker
7 | import org.futo.circles.core.feature.share.BaseShareActivity
8 | import org.futo.circles.core.model.SelectRoomTypeArg
9 |
10 | @AndroidEntryPoint
11 | class ShareWithGroupActivity : BaseShareActivity() {
12 |
13 | override val titleResId: Int = R.string.share_with_group
14 |
15 | override val roomsPicker: RoomsPicker =
16 | SelectRoomsFragment.create(SelectRoomTypeArg.GroupsJoined)
17 |
18 | override fun getShareRoomsIds(): List = roomsPicker.getSelectedRooms().map { it.id }
19 |
20 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/picker/gallery/media/list/holder/GalleryTimelineLoadingViewHolder.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.picker.gallery.media.list.holder
2 |
3 | import android.view.ViewGroup
4 | import org.futo.circles.core.base.list.ViewBindingHolder
5 | import org.futo.circles.core.databinding.ListItemTimelineLoadingBinding
6 | import org.futo.circles.core.model.GalleryTimelineListItem
7 | import org.futo.circles.core.model.GalleryTimelineLoadingListItem
8 |
9 |
10 | class GalleryTimelineLoadingViewHolder(
11 | parent: ViewGroup,
12 | ) : GalleryTimelineItemViewHolder(inflate(parent, ListItemTimelineLoadingBinding::inflate)) {
13 |
14 | private companion object : ViewBindingHolder
15 |
16 | override fun bind(item: GalleryTimelineListItem) {
17 | if (item !is GalleryTimelineLoadingListItem) return
18 | }
19 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/base/Constants.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.base
2 |
3 | import org.futo.circles.core.provider.MatrixSessionProvider
4 |
5 | const val FILE_PROVIDER_AUTHORITY_EXTENSION = ".provider"
6 | const val MediaCaptionFieldKey = "caption"
7 | const val READ_ONLY_ROLE = -10
8 |
9 | val PUSHER_APP_ID = "${CirclesAppConfig.appId}.android"
10 |
11 | fun getPusherUrl(): String = "https://sygnal.${getCirclesDomain()}/_matrix/push/v1/notify"
12 |
13 | const val DEFAULT_PUSH_GATEWAY = "https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify"
14 |
15 | fun getCirclesDomain(): String {
16 | val homeServerUrl = MatrixSessionProvider.currentSession?.sessionParams?.homeServerUrl ?: ""
17 | return CirclesAppConfig.serverDomains().firstOrNull { homeServerUrl.contains(it) }
18 | ?: CirclesAppConfig.serverDomains().first()
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/SearchViewExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import androidx.appcompat.widget.SearchView
4 | import kotlinx.coroutines.flow.MutableStateFlow
5 | import kotlinx.coroutines.flow.StateFlow
6 |
7 | fun SearchView.getQueryTextChangeStateFlow(onTextChanged: ((String) -> Unit)? = null): StateFlow {
8 |
9 | val query = MutableStateFlow("")
10 |
11 | setOnQueryTextListener(object : SearchView.OnQueryTextListener {
12 | override fun onQueryTextSubmit(query: String?): Boolean {
13 | return true
14 | }
15 |
16 | override fun onQueryTextChange(newText: String): Boolean {
17 | onTextChanged?.invoke(newText)
18 | query.value = newText
19 | return true
20 | }
21 | })
22 |
23 | return query
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_ban.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/core/src/main/res/drawable/ic_person_remove.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/base/SingleEventLiveData.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.base
2 |
3 | import androidx.annotation.MainThread
4 | import androidx.lifecycle.LifecycleOwner
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.Observer
7 | import java.util.concurrent.atomic.AtomicBoolean
8 |
9 |
10 | class SingleEventLiveData : MutableLiveData() {
11 | private val pending = AtomicBoolean(false)
12 |
13 | @MainThread
14 | override fun observe(owner: LifecycleOwner, observer: Observer) {
15 | super.observe(owner) { t ->
16 | if (pending.compareAndSet(true, false)) {
17 | observer.onChanged(t)
18 | }
19 | }
20 | }
21 |
22 | @MainThread
23 | override fun setValue(t: T?) {
24 | pending.set(true)
25 | super.setValue(t)
26 | }
27 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/MatrixUserExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import org.futo.circles.core.utils.UserIdUtils
4 | import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
5 | import org.matrix.android.sdk.api.session.room.sender.SenderInfo
6 | import org.matrix.android.sdk.api.session.user.model.User
7 |
8 |
9 | fun User.notEmptyDisplayName(): String = getName(userId, displayName)
10 |
11 | fun RoomMemberSummary.notEmptyDisplayName(): String = getName(userId, displayName)
12 |
13 | fun SenderInfo.notEmptyDisplayName(): String = getName(userId, displayName)
14 |
15 | private fun getName(userId: String, displayName: String?): String {
16 | val name = displayName?.takeIf { it.isNotEmpty() }
17 | ?: userId.replace("@", "").substringBefore(":")
18 | return UserIdUtils.removeDomainSuffix(name)
19 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/TimelineEventExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import org.futo.circles.core.model.PostContentType
4 | import org.matrix.android.sdk.api.session.events.model.EventType
5 | import org.matrix.android.sdk.api.session.events.model.toModel
6 | import org.matrix.android.sdk.api.session.room.model.message.MessageContent
7 | import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
8 | import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
9 |
10 |
11 | fun TimelineEvent.getPostContentType(): PostContentType? {
12 | val messageType = if (root.getClearType() == EventType.MESSAGE) root.getClearContent()
13 | .toModel()?.msgType
14 | else getLastMessageContent()?.msgType
15 | return PostContentType.entries.firstOrNull { it.typeKey == messageType }
16 | }
--------------------------------------------------------------------------------
/core/src/main/res/layout/list_item_access_level.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/core/src/main/res/layout/list_item_invite_notification.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
20 |
21 |
--------------------------------------------------------------------------------
/settings/src/main/java/org/futo/circles/settings/view/EditEmailView.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.settings.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.LayoutInflater
6 | import androidx.constraintlayout.widget.ConstraintLayout
7 | import org.futo.circles.settings.databinding.ViewEditEmailBinding
8 |
9 |
10 | class EditEmailView(
11 | context: Context,
12 | attrs: AttributeSet? = null,
13 | ) : ConstraintLayout(context, attrs) {
14 |
15 | private val binding =
16 | ViewEditEmailBinding.inflate(LayoutInflater.from(context), this)
17 |
18 | fun setData(
19 | email: String,
20 | onRemove: (String) -> Unit,
21 | ) {
22 | with(binding) {
23 | tvEmail.text = email
24 | binding.ivRemove.setOnClickListener { onRemove.invoke(email) }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/feature/splash/SplashFragment.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.feature.splash
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.navigation.fragment.findNavController
7 | import org.futo.circles.R
8 | import org.futo.circles.core.extensions.navigateSafe
9 | import org.futo.circles.core.provider.MatrixSessionProvider
10 |
11 | class SplashFragment : Fragment(R.layout.fragment_splash) {
12 |
13 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
14 | super.onViewCreated(view, savedInstanceState)
15 | val destination = MatrixSessionProvider.currentSession?.let {
16 | SplashFragmentDirections.toHomeFragment()
17 | } ?: SplashFragmentDirections.toLogInFragment()
18 |
19 | findNavController().navigateSafe(destination)
20 | }
21 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/glide/LocalFileHelper.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.glide
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import androidx.documentfile.provider.DocumentFile
6 | import org.matrix.android.sdk.api.extensions.orFalse
7 | import java.io.InputStream
8 |
9 | class LocalFileHelper(private val context: Context) {
10 |
11 | fun isLocalFile(fileUri: String?): Boolean {
12 | return fileUri
13 | ?.let { Uri.parse(it) }
14 | ?.let { DocumentFile.fromSingleUri(context, it) }
15 | ?.exists()
16 | .orFalse()
17 | }
18 |
19 | fun openInputStream(fileUri: String?): InputStream? {
20 | return fileUri
21 | ?.takeIf { isLocalFile(it) }
22 | ?.let { Uri.parse(it) }
23 | ?.let { context.contentResolver.openInputStream(it) }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/view/NetworkRequiredButton.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import android.view.View.OnClickListener
7 | import com.google.android.material.button.MaterialButton
8 | import org.futo.circles.core.base.NetworkObserver
9 |
10 | class NetworkRequiredButton(
11 | context: Context,
12 | attrs: AttributeSet? = null
13 | ) : MaterialButton(context, attrs), OnClickListener {
14 |
15 | private var customClickListener: OnClickListener? = null
16 |
17 | override fun setOnClickListener(l: OnClickListener?) {
18 | customClickListener = l
19 | super.setOnClickListener(this)
20 | }
21 |
22 | override fun onClick(v: View?) {
23 | if (!NetworkObserver.isConnected()) return
24 | customClickListener?.onClick(v)
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/org/futo/circles/model/CircleListItem.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.model
2 |
3 | import org.futo.circles.core.base.list.IdEntity
4 | import org.futo.circles.core.model.RoomInfo
5 |
6 | sealed class CircleListItem : IdEntity
7 | data class CirclesHeaderItem(
8 | val titleRes: Int
9 | ) : CircleListItem() {
10 | override val id: String = titleRes.toString()
11 | }
12 |
13 | data class JoinedCircleListItem(
14 | override val id: String,
15 | val timelineId: String,
16 | val info: RoomInfo,
17 | val followingCount: Int,
18 | val followedByCount: Int,
19 | val unreadCount: Int,
20 | val knockRequestsCount: Int
21 | ) : CircleListItem()
22 |
23 | data class CircleInvitesNotificationListItem(
24 | val invitesCount: Int,
25 | val knocksCount: Int
26 | ) : CircleListItem() {
27 | override val id: String = "CircleInvitesNotificationListItem"
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/extensions/MediaContentDataExtensions.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.extensions
2 |
3 | import android.util.Size
4 | import android.widget.ImageView
5 | import org.futo.circles.core.model.MediaContent
6 | import org.futo.circles.core.model.MediaFileData
7 |
8 | fun MediaContent.loadEncryptedThumbOrFullIntoWithAspect(imageView: ImageView) {
9 | val fileContent = thumbnailFileData ?: mediaFileData
10 | fileContent.loadEncryptedIntoWithAspect(imageView, thumbHash)
11 | }
12 |
13 | fun MediaFileData.loadEncryptedIntoWithAspect(
14 | imageView: ImageView,
15 | thumbHash: String? = null
16 | ) {
17 | imageView.post {
18 | if (fileUrl.startsWith(UriContentScheme)) {
19 | imageView.loadImage(fileUrl)
20 | } else {
21 | imageView.loadEncryptedImage(this, Size(width, height), thumbHash = thumbHash)
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/circles/following/list/FollowingAdapter.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.circles.following.list
2 |
3 | import android.view.ViewGroup
4 | import org.futo.circles.core.base.list.BaseRvAdapter
5 | import org.futo.circles.core.model.FollowingListItem
6 |
7 | class FollowingAdapter(
8 | private val onRemoveClicked: (FollowingListItem) -> Unit
9 | ) : BaseRvAdapter(DefaultIdEntityCallback()) {
10 |
11 | override fun onCreateViewHolder(
12 | parent: ViewGroup,
13 | viewType: Int
14 | ): FollowingViewHolder = FollowingViewHolder(
15 | parent = parent,
16 | onRemoveClicked = { position -> onRemoveClicked(getItem(position)) }
17 | )
18 |
19 | override fun onBindViewHolder(holder: FollowingViewHolder, position: Int) {
20 | holder.bind(getItem(position))
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/core/src/main/java/org/futo/circles/core/feature/room/select/list/SelectRoomsAdapter.kt:
--------------------------------------------------------------------------------
1 | package org.futo.circles.core.feature.room.select.list
2 |
3 | import android.view.ViewGroup
4 | import org.futo.circles.core.base.list.BaseRvAdapter
5 | import org.futo.circles.core.model.SelectableRoomListItem
6 |
7 | class SelectRoomsAdapter(
8 | private val onRoomSelected: (SelectableRoomListItem) -> Unit
9 | ) : BaseRvAdapter(DefaultIdEntityCallback()) {
10 |
11 | override fun onCreateViewHolder(
12 | parent: ViewGroup,
13 | viewType: Int
14 | ): SelectRoomsViewHolder = SelectRoomsViewHolder(
15 | parent,
16 | onCircleClicked = { position -> onRoomSelected(getItem(position)) })
17 |
18 |
19 | override fun onBindViewHolder(holder: SelectRoomsViewHolder, position: Int) {
20 | holder.bind(getItem(position))
21 | }
22 |
23 | }
--------------------------------------------------------------------------------