Skip to content
This repository has been archived by the owner on Sep 23, 2024. It is now read-only.

Commit

Permalink
Adding language option when creating a new post (#526)
Browse files Browse the repository at this point in the history
- Adding a option to specify which language you are using when creating
a new post
- Updating account info when starting the app
- Adding default language to a user's prefs

---------

Co-authored-by: John Oberhauser <j.git-global@obez.io>
  • Loading branch information
JohnOberhauser and John Oberhauser authored May 15, 2024
1 parent 81d4fd6 commit f8def03
Show file tree
Hide file tree
Showing 22 changed files with 201 additions and 68 deletions.
3 changes: 3 additions & 0 deletions app/src/main/kotlin/social/firefly/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ import social.firefly.core.navigation.NavigationDestination
import social.firefly.core.navigation.usecases.NavigateTo
import social.firefly.core.repository.mastodon.TimelineRepository
import social.firefly.core.share.ShareInfo
import social.firefly.core.usecase.mastodon.auth.UpdateAllLoggedInAccounts
import social.firefly.ui.AppState

class MainViewModel(
private val navigateTo: NavigateTo,
private val userPreferencesDatastoreManager: UserPreferencesDatastoreManager,
private val timelineRepository: TimelineRepository,
private val eventRelay: EventRelay,
private val updateAllLoggedInAccounts: UpdateAllLoggedInAccounts,
appPreferencesDatastore: AppPreferencesDatastore,
) : ViewModel() {

Expand All @@ -47,6 +49,7 @@ class MainViewModel(
if (userPreferencesDatastoreManager.isLoggedInToAtLeastOneAccount) {
navigateTo(NavigationDestination.Tabs)
handleIntent(intent)
updateAllLoggedInAccounts()
} else {
navigateTo(NavigationDestination.Auth)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class UserPreferencesDatastore internal constructor(
val serializedPushKeys: Flow<String> = dataStore.data.mapLatest { it.serializedPushKeys }
val lastSeenHomeStatusId: Flow<String> = dataStore.data.mapLatest { it.lastSeenHomeStatusId }
val threadType: Flow<ThreadType> = dataStore.data.mapLatest { it.threadType }.distinctUntilChanged()
val defaultLanguage: Flow<String> = dataStore.data.mapLatest { it.defaultLanguage }

suspend fun saveAvatarUrl(url: String) {
dataStore.updateData {
Expand Down Expand Up @@ -93,6 +94,14 @@ class UserPreferencesDatastore internal constructor(
}
}

suspend fun saveDefaultLanguage(language: String) {
dataStore.updateData {
it.toBuilder()
.setDefaultLanguage(language)
.build()
}
}

companion object {
@Suppress("MaxLineLength")
const val HOST_NAME_REGEX = "[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+)+"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class UserPreferencesDatastoreManager(
accountId: String,
userName: String,
avatarUrl: String,
defaultLanguage: String,
) {
require(UserPreferencesDatastore.HOST_NAME_REGEX.toRegex().matches(domain))
val fileName = "$domain-$accountId-$counter-prefs.pb"
Expand All @@ -83,6 +84,7 @@ class UserPreferencesDatastoreManager(
).apply {
saveUserName(userName)
saveAvatarUrl(avatarUrl)
saveDefaultLanguage(defaultLanguage)
}

_dataStores.update { it + newDataStore }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ message UserPreferences {
ThreadType thread_type = 9;
string avatar_url = 11;
string user_name = 12;
string default_language = 13;
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ object FfIcons {
@Composable
fun gear() = painterResource(id = R.drawable.gear)

@Composable
fun globe() = painterResource(id = R.drawable.globe)

@Composable
fun globeHemisphereWest() = painterResource(id = R.drawable.globe_hemisphere_west)

Expand Down
9 changes: 9 additions & 0 deletions core/designsystem/src/main/res/drawable/globe.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M128,24h0A104,104 0,1 0,232 128,104.12 104.12,0 0,0 128,24ZM216,128a87.61,87.61 0,0 1,-3.33 24L174.16,152a157.44,157.44 0,0 0,0 -48h38.51A87.61,87.61 0,0 1,216 128ZM102,168L154,168a115.11,115.11 0,0 1,-26 45A115.27,115.27 0,0 1,102 168ZM98.1,152a140.84,140.84 0,0 1,0 -48h59.88a140.84,140.84 0,0 1,0 48ZM40,128a87.61,87.61 0,0 1,3.33 -24L81.84,104a157.44,157.44 0,0 0,0 48L43.33,152A87.61,87.61 0,0 1,40 128ZM154,88L102,88a115.11,115.11 0,0 1,26 -45A115.27,115.27 0,0 1,154 88ZM206.33,88L170.71,88a135.28,135.28 0,0 0,-22.3 -45.6A88.29,88.29 0,0 1,206.37 88ZM107.59,42.4A135.28,135.28 0,0 0,85.29 88L49.63,88A88.29,88.29 0,0 1,107.59 42.4ZM49.63,168L85.29,168a135.28,135.28 0,0 0,22.3 45.6A88.29,88.29 0,0 1,49.63 168ZM148.41,213.6a135.28,135.28 0,0 0,22.3 -45.6h35.66A88.29,88.29 0,0 1,148.41 213.6Z"
android:fillColor="#000000"/>
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ fun FfDropDownMenu(
Box(
modifier = Modifier
.clip(RoundedCornerShape(8.dp)) // rounded corner is for the ripple
.clickable { if (canExpand) expanded.value = true },
.clickable { if (canExpand) expanded.value = true }
.padding(8.dp),
) {
// padding is for the ripple
Row(modifier = Modifier.padding(padding)) {
Expand Down
4 changes: 0 additions & 4 deletions core/ui/common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@
<string name="more_info_content_description">more info</string>
<string name="recommendations_discover_more">Discover more</string>

<string name="visibility_public">Public</string>
<string name="visibility_unlisted">Unlisted</string>
<string name="visibility_private">Private</string>
<string name="visibility_direct">Direct</string>
<string name="theres_nothing_here">There\'s nothing here</string>

<string name="follow_button">Follow</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,14 @@ class Login(
accessToken = accessToken,
baseUrl = host,
)
val defaultLanguage = account.source?.defaultLanguage ?: ""
userPreferencesDatastoreManager.createNewUserDatastore(
domain = host,
accessToken = accessToken,
accountId = account.accountId,
userName = account.displayName,
avatarUrl = account.avatarUrl,
defaultLanguage = defaultLanguage,
)
withContext(Dispatchers.IO) {
databaseDelegate.clearAllTables()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class UpdateAllLoggedInAccounts(
}?.apply {
saveAvatarUrl(account.avatarUrl)
saveUserName(account.username)
val defaultLanguage = account.source?.defaultLanguage ?: ""
saveDefaultLanguage(defaultLanguage)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class PostStatus internal constructor(
pollCreate: PollCreate?,
contentWarningText: String?,
inReplyToId: String?,
languageCode: String?,
) = externalScope.async(dispatcherIo) {
try {
// asynchronously update all attachment descriptions before sending post
Expand Down Expand Up @@ -76,6 +77,7 @@ class PostStatus internal constructor(
contentWarningText
},
inReplyToId = inReplyToId,
language = languageCode,
),
)
saveStatusToDatabase(status)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class PostStatusTest : BaseUseCaseTest() {
pollCreate = null,
contentWarningText = null,
inReplyToId = null,
languageCode = null,
)
},
verifyBlock = {
Expand All @@ -68,6 +69,7 @@ class PostStatusTest : BaseUseCaseTest() {
pollCreate = null,
contentWarningText = null,
inReplyToId = null,
languageCode = null
)
},
verifyBlock = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ interface NewPostInteractions {
fun onPostClicked()
fun onEditClicked()
fun onVisibilitySelected(statusVisibility: StatusVisibility)
fun onLanguageSelected(code: String)
}

object NewPostInteractionsNoOp : social.firefly.feature.post.NewPostInteractions {
object NewPostInteractionsNoOp : NewPostInteractions {
override fun onScreenViewed() = Unit
override fun onUploadImageClicked() = Unit
override fun onUploadMediaClicked() = Unit
override fun onPostClicked() = Unit
override fun onEditClicked() = Unit
override fun onVisibilitySelected(statusVisibility: StatusVisibility) = Unit
override fun onLanguageSelected(code: String) = Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ val newPostModule = module {
)

viewModel { parametersHolder ->
social.firefly.feature.post.NewPostViewModel(
NewPostViewModel(
analytics = get(),
replyStatusId = parametersHolder[0],
editStatusId = parametersHolder[1],
Expand All @@ -34,6 +34,7 @@ val newPostModule = module {
showSnackbar = get(),
getLoggedInUserAccountId = get(),
accountRepository = get(),
userPreferencesDatastoreManager = get(),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.CircleShape
Expand Down Expand Up @@ -71,6 +72,7 @@ import social.firefly.core.ui.common.transparentTextFieldColors
import social.firefly.core.ui.common.utils.getWindowHeightClass
import social.firefly.feature.post.bottombar.BottomBar
import social.firefly.feature.post.bottombar.BottomBarState
import social.firefly.feature.post.bottombar.VisibilityDropDownButton
import social.firefly.feature.post.media.MediaInteractions
import social.firefly.feature.post.poll.Poll
import social.firefly.feature.post.poll.PollBar
Expand Down Expand Up @@ -127,7 +129,7 @@ private fun NewPostScreen(
mediaInteractions: MediaInteractions,
pollInteractions: PollInteractions,
contentWarningInteractions: ContentWarningInteractions,
newPostInteractions: social.firefly.feature.post.NewPostInteractions,
newPostInteractions: NewPostInteractions,
) {
Box(
modifier =
Expand Down Expand Up @@ -183,7 +185,7 @@ private fun CompactNewPostScreenContent(
mediaInteractions: MediaInteractions,
pollInteractions: PollInteractions,
contentWarningInteractions: ContentWarningInteractions,
newPostInteractions: social.firefly.feature.post.NewPostInteractions,
newPostInteractions: NewPostInteractions,
) {
Row {
Box(
Expand Down Expand Up @@ -231,6 +233,8 @@ private fun NewPostScreenContent(
onPostClicked = newPostInteractions::onPostClicked,
onEditClicked = newPostInteractions::onEditClicked,
sendButtonEnabled = newPostUiState.sendButtonEnabled,
visibility = newPostUiState.visibility,
newPostInteractions = newPostInteractions,
)

Spacer(modifier = Modifier.height(FfSpacing.sm))
Expand Down Expand Up @@ -279,8 +283,7 @@ private fun NewPostScreenContent(
contentWarningInteractions = contentWarningInteractions,
onUploadImageClicked = newPostInteractions::onUploadImageClicked,
onUploadMediaClicked = newPostInteractions::onUploadMediaClicked,
visibility = newPostUiState.visibility,
onVisibilitySelected = newPostInteractions::onVisibilitySelected,
onLanguageSelected = newPostInteractions::onLanguageSelected,
)
}
}
Expand All @@ -306,9 +309,16 @@ private fun TopBar(
onPostClicked: () -> Unit,
onEditClicked: () -> Unit,
sendButtonEnabled: Boolean,
visibility: StatusVisibility,
newPostInteractions: NewPostInteractions,
) {
FfCloseableTopAppBar(
actions = {
VisibilityDropDownButton(
visibility = visibility,
onVisibilitySelected = newPostInteractions::onVisibilitySelected,
)
Spacer(modifier = Modifier.width(8.dp))
SubmitButton(
modifier = Modifier.padding(end = 16.dp),
onPostClicked = if (!statusUiState.editStatusId.isNullOrBlank())
Expand Down Expand Up @@ -339,7 +349,6 @@ private fun SubmitButton(
}
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
private fun MainBox(
statusUiState: StatusUiState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package social.firefly.feature.post

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
Expand All @@ -16,6 +19,7 @@ import social.firefly.common.utils.FileType
import social.firefly.common.utils.StringFactory
import social.firefly.common.utils.edit
import social.firefly.core.analytics.NewPostAnalytics
import social.firefly.core.datastore.UserPreferencesDatastoreManager
import social.firefly.core.model.StatusVisibility
import social.firefly.core.model.request.PollCreate
import social.firefly.core.navigation.usecases.PopNavBackstack
Expand All @@ -24,13 +28,15 @@ import social.firefly.core.repository.mastodon.AccountRepository
import social.firefly.core.usecase.mastodon.account.GetLoggedInUserAccountId
import social.firefly.core.usecase.mastodon.status.EditStatus
import social.firefly.core.usecase.mastodon.status.PostStatus
import social.firefly.feature.post.bottombar.BottomBarState
import social.firefly.feature.post.bottombar.LocaleUiState
import social.firefly.feature.post.media.MediaDelegate
import social.firefly.feature.post.poll.PollDelegate
import social.firefly.feature.post.poll.PollStyle
import social.firefly.feature.post.status.StatusDelegate
import timber.log.Timber
import java.util.Locale

@OptIn(ExperimentalCoroutinesApi::class)
class NewPostViewModel(
private val analytics: NewPostAnalytics,
private val replyStatusId: String?,
Expand All @@ -41,7 +47,8 @@ class NewPostViewModel(
private val editStatus: EditStatus,
private val popNavBackstack: PopNavBackstack,
private val showSnackbar: ShowSnackbar,
) : ViewModel(), social.firefly.feature.post.NewPostInteractions, KoinComponent {
private val userPreferencesDatastoreManager: UserPreferencesDatastoreManager,
) : ViewModel(), NewPostInteractions, KoinComponent {

val statusDelegate: StatusDelegate by inject {
parametersOf(
Expand Down Expand Up @@ -77,7 +84,7 @@ class NewPostViewModel(
) { imagesStates, pollUiState, statusUiState ->
val images = imagesStates.filter { it.fileType == FileType.IMAGE }
val videos = imagesStates.filter { it.fileType == FileType.VIDEO }
BottomBarState(
newPostUiState.value.bottomBarState.copy(
imageButtonEnabled = videos.isEmpty() && images.size < MAX_IMAGES && pollUiState == null,
videoButtonEnabled = images.isEmpty() && pollUiState == null,
pollButtonEnabled = images.isEmpty() && videos.isEmpty(),
Expand Down Expand Up @@ -136,6 +143,49 @@ class NewPostViewModel(
}
}
}

viewModelScope.launch {
val defaultLanguageCode = userPreferencesDatastoreManager
.activeUserDatastore
.flatMapLatest { it.defaultLanguage }
.first()
.ifBlank {
Locale.getDefault().language
}

val availableLocales = Locale.getAvailableLocales()
.filter { locale ->
locale.country.isNullOrBlank() &&
locale.script.isNullOrBlank() &&
locale.variant.isNullOrBlank()
}.sortedBy { locale ->
locale.displayName
}.map { locale ->
LocaleUiState(
displayName = "${locale.displayName} (${locale.getDisplayName(locale)})",
code = locale.language
)
}

_newPostUiState.edit {
copy(
bottomBarState = newPostUiState.value.bottomBarState.copy(
language = defaultLanguageCode,
availableLocales = availableLocales,
)
)
}
}
}

override fun onLanguageSelected(code: String) {
_newPostUiState.edit {
copy(
bottomBarState = newPostUiState.value.bottomBarState.copy(
language = code,
)
)
}
}

override fun onVisibilitySelected(statusVisibility: StatusVisibility) {
Expand Down Expand Up @@ -169,6 +219,7 @@ class NewPostViewModel(
},
contentWarningText = statusDelegate.uiState.value.contentWarningText,
inReplyToId = replyStatusId,
languageCode = newPostUiState.value.bottomBarState.language,
)

onStatusPosted()
Expand Down
Loading

0 comments on commit f8def03

Please sign in to comment.