Add language dropdown to compose view (#2651)
* Add UI for selecting post language * Apply selected language when sending status * Save/restore post language with drafts * Fall back to english if the configured language isn't found in the locale list (no-NB) * Remove comment about no_NB * Move language dropdown to top of compose view * Preserve language when redrafting * Set default language to target post's language when replying * Add Tusky license header to new source file * Tweak language dropdown button width
This commit is contained in:
parent
c638ad7e6b
commit
0041acf2d4
28 changed files with 1140 additions and 28 deletions
|
@ -0,0 +1,43 @@
|
|||
/* Copyright 2022 Tusky contributors
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.TextView
|
||||
import com.keylesspalace.tusky.util.ThemeUtils
|
||||
import java.util.Locale
|
||||
|
||||
class LocaleAdapter(context: Context, resource: Int, locales: List<Locale>) : ArrayAdapter<Locale>(context, resource, locales) {
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
return (super.getView(position, convertView, parent) as TextView).apply {
|
||||
setTextColor(ThemeUtils.getColor(context, android.R.attr.textColorTertiary))
|
||||
typeface = Typeface.DEFAULT_BOLD
|
||||
text = super.getItem(position)?.language?.uppercase()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
return (super.getDropDownView(position, convertView, parent) as TextView).apply {
|
||||
setTextColor(ThemeUtils.getColor(context, android.R.attr.textColorTertiary))
|
||||
val locale = super.getItem(position)
|
||||
text = "${locale?.displayLanguage} (${locale?.getDisplayLanguage(locale)})"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,6 +35,7 @@ import android.view.KeyEvent
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupMenu
|
||||
|
@ -65,6 +66,7 @@ import com.keylesspalace.tusky.BaseActivity
|
|||
import com.keylesspalace.tusky.BuildConfig
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.adapter.EmojiAdapter
|
||||
import com.keylesspalace.tusky.adapter.LocaleAdapter
|
||||
import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener
|
||||
import com.keylesspalace.tusky.components.compose.dialog.makeCaptionDialog
|
||||
import com.keylesspalace.tusky.components.compose.dialog.showAddPollDialog
|
||||
|
@ -244,6 +246,7 @@ class ComposeActivity :
|
|||
binding.composeScheduleView.setDateTime(composeOptions?.scheduledAt)
|
||||
}
|
||||
|
||||
setupLanguageSpinner(getInitialLanguage(composeOptions?.language))
|
||||
setupComposeField(preferences, viewModel.startingText)
|
||||
setupContentWarningField(composeOptions?.contentWarning)
|
||||
setupPollView()
|
||||
|
@ -476,6 +479,40 @@ class ComposeActivity :
|
|||
binding.addPollTextActionTextView.setOnClickListener { openPollDialog() }
|
||||
}
|
||||
|
||||
private fun setupLanguageSpinner(initialLanguage: String?) {
|
||||
val locales = Locale.getAvailableLocales()
|
||||
.filter { it.country.isNullOrEmpty() && it.script.isNullOrEmpty() && it.variant.isNullOrEmpty() } // Only "base" languages, "en" but not "en_DK"
|
||||
var currentLocaleIndex = locales.indexOfFirst { it.language == initialLanguage }
|
||||
if (currentLocaleIndex < 0) {
|
||||
Log.e(TAG, "Error looking up language tag '$initialLanguage', falling back to english")
|
||||
currentLocaleIndex = locales.indexOfFirst { it.language == "en" }
|
||||
}
|
||||
|
||||
val context = this
|
||||
binding.composePostLanguageButton.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
|
||||
viewModel.postLanguage = (parent.adapter.getItem(position) as Locale).language
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>) {
|
||||
parent.setSelection(locales.indexOfFirst { it.language == getInitialLanguage() })
|
||||
}
|
||||
}
|
||||
binding.composePostLanguageButton.apply {
|
||||
adapter = LocaleAdapter(context, android.R.layout.simple_spinner_dropdown_item, locales)
|
||||
setSelection(currentLocaleIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInitialLanguage(language: String? = null): String {
|
||||
return if (language.isNullOrEmpty()) {
|
||||
// Setting the application ui preference sets the default locale
|
||||
Locale.getDefault().language
|
||||
} else {
|
||||
language
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupActionBar() {
|
||||
setSupportActionBar(binding.toolbar)
|
||||
supportActionBar?.run {
|
||||
|
@ -793,6 +830,10 @@ class ComposeActivity :
|
|||
return length
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
val selectedLanguage: String?
|
||||
get() = viewModel.postLanguage
|
||||
|
||||
private fun updateVisibleCharactersLeft() {
|
||||
val remainingLength = maximumTootCharacters - calculateTextLength()
|
||||
binding.composeCharactersLeftView.text = String.format(Locale.getDefault(), "%d", remainingLength)
|
||||
|
@ -1128,7 +1169,8 @@ class ComposeActivity :
|
|||
var scheduledAt: String? = null,
|
||||
var sensitive: Boolean? = null,
|
||||
var poll: NewPoll? = null,
|
||||
var modifiedInitialState: Boolean? = null
|
||||
var modifiedInitialState: Boolean? = null,
|
||||
var language: String? = null,
|
||||
) : Parcelable
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -68,6 +68,7 @@ class ComposeViewModel @Inject constructor(
|
|||
private var replyingStatusAuthor: String? = null
|
||||
private var replyingStatusContent: String? = null
|
||||
internal var startingText: String? = null
|
||||
internal var postLanguage: String? = null
|
||||
private var draftId: Int = 0
|
||||
private var scheduledTootId: String? = null
|
||||
private var startingContentWarning: String = ""
|
||||
|
@ -261,7 +262,8 @@ class ComposeViewModel @Inject constructor(
|
|||
mediaDescriptions = mediaDescriptions,
|
||||
poll = poll.value,
|
||||
failedToSend = false,
|
||||
scheduledAt = scheduledAt.value
|
||||
scheduledAt = scheduledAt.value,
|
||||
language = postLanguage,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -308,7 +310,8 @@ class ComposeViewModel @Inject constructor(
|
|||
draftId = draftId,
|
||||
idempotencyKey = randomAlphanumericString(16),
|
||||
retries = 0,
|
||||
mediaProcessed = mediaProcessed
|
||||
mediaProcessed = mediaProcessed,
|
||||
language = postLanguage,
|
||||
)
|
||||
|
||||
serviceClient.sendToot(tootToSend)
|
||||
|
@ -426,6 +429,7 @@ class ComposeViewModel @Inject constructor(
|
|||
draftId = composeOptions?.draftId ?: 0
|
||||
scheduledTootId = composeOptions?.scheduledTootId
|
||||
startingText = composeOptions?.content
|
||||
postLanguage = composeOptions?.language
|
||||
|
||||
val tootVisibility = composeOptions?.visibility ?: Status.Visibility.UNKNOWN
|
||||
if (tootVisibility.num != Status.Visibility.UNKNOWN.num) {
|
||||
|
|
|
@ -94,7 +94,8 @@ data class ConversationStatusEntity(
|
|||
val expanded: Boolean,
|
||||
val collapsed: Boolean,
|
||||
val muted: Boolean,
|
||||
val poll: Poll?
|
||||
val poll: Poll?,
|
||||
val language: String?,
|
||||
) {
|
||||
|
||||
fun toViewData(): StatusViewData.Concrete {
|
||||
|
@ -125,7 +126,8 @@ data class ConversationStatusEntity(
|
|||
pinned = false,
|
||||
muted = muted,
|
||||
poll = poll,
|
||||
card = null
|
||||
card = null,
|
||||
language = language,
|
||||
),
|
||||
isExpanded = expanded,
|
||||
isShowingContent = showingHiddenContent,
|
||||
|
@ -167,7 +169,8 @@ fun Status.toEntity() =
|
|||
expanded = false,
|
||||
collapsed = true,
|
||||
muted = muted ?: false,
|
||||
poll = poll
|
||||
poll = poll,
|
||||
language = language,
|
||||
)
|
||||
|
||||
fun Conversation.toEntity(accountId: Long, order: Int) =
|
||||
|
|
|
@ -85,6 +85,7 @@ fun StatusViewData.Concrete.toConversationStatusEntity(
|
|||
expanded = expanded,
|
||||
collapsed = collapsed,
|
||||
muted = muted,
|
||||
poll = poll
|
||||
poll = poll,
|
||||
language = status.language,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -61,7 +61,8 @@ class DraftHelper @Inject constructor(
|
|||
mediaDescriptions: List<String?>,
|
||||
poll: NewPoll?,
|
||||
failedToSend: Boolean,
|
||||
scheduledAt: String?
|
||||
scheduledAt: String?,
|
||||
language: String?,
|
||||
) = withContext(Dispatchers.IO) {
|
||||
val externalFilesDir = context.getExternalFilesDir("Tusky")
|
||||
|
||||
|
@ -118,7 +119,8 @@ class DraftHelper @Inject constructor(
|
|||
attachments = attachments,
|
||||
poll = poll,
|
||||
failedToSend = failedToSend,
|
||||
scheduledAt = scheduledAt
|
||||
scheduledAt = scheduledAt,
|
||||
language = language,
|
||||
)
|
||||
|
||||
draftDao.insertOrReplace(draft)
|
||||
|
|
|
@ -107,7 +107,8 @@ class DraftsActivity : BaseActivity(), DraftActionListener {
|
|||
poll = draft.poll,
|
||||
sensitive = draft.sensitive,
|
||||
visibility = draft.visibility,
|
||||
scheduledAt = draft.scheduledAt
|
||||
scheduledAt = draft.scheduledAt,
|
||||
language = draft.language,
|
||||
)
|
||||
|
||||
bottomSheet.state = BottomSheetBehavior.STATE_HIDDEN
|
||||
|
@ -145,7 +146,8 @@ class DraftsActivity : BaseActivity(), DraftActionListener {
|
|||
poll = draft.poll,
|
||||
sensitive = draft.sensitive,
|
||||
visibility = draft.visibility,
|
||||
scheduledAt = draft.scheduledAt
|
||||
scheduledAt = draft.scheduledAt,
|
||||
language = draft.language,
|
||||
)
|
||||
|
||||
startActivity(ComposeActivity.startIntent(this, composeOptions))
|
||||
|
|
|
@ -365,6 +365,7 @@ public class NotificationHelper {
|
|||
composeOptions.setReplyingStatusContent(citedText);
|
||||
composeOptions.setMentionedUsernames(mentionedUsernames);
|
||||
composeOptions.setModifiedInitialState(true);
|
||||
composeOptions.setLanguage(actionableStatus.getLanguage());
|
||||
|
||||
Intent composeIntent = ComposeActivity.startIntent(
|
||||
context,
|
||||
|
|
|
@ -216,7 +216,8 @@ class SearchStatusesFragment : SearchFragment<StatusViewData.Concrete>(), Status
|
|||
contentWarning = actionableStatus.spoilerText,
|
||||
mentionedUsernames = mentionedUsernames,
|
||||
replyingStatusAuthor = actionableStatus.account.localUsername,
|
||||
replyingStatusContent = status.content.toString()
|
||||
replyingStatusContent = status.content.toString(),
|
||||
language = actionableStatus.language,
|
||||
)
|
||||
)
|
||||
bottomSheetActivity?.startActivityWithSlideInAnimation(intent)
|
||||
|
@ -461,7 +462,8 @@ class SearchStatusesFragment : SearchFragment<StatusViewData.Concrete>(), Status
|
|||
contentWarning = redraftStatus.spoilerText,
|
||||
mediaAttachments = redraftStatus.attachments,
|
||||
sensitive = redraftStatus.sensitive,
|
||||
poll = redraftStatus.poll?.toNewPoll(status.createdAt)
|
||||
poll = redraftStatus.poll?.toNewPoll(status.createdAt),
|
||||
language = redraftStatus.language,
|
||||
)
|
||||
)
|
||||
startActivity(intent)
|
||||
|
|
|
@ -99,7 +99,8 @@ fun Placeholder.toEntity(timelineUserId: Long): TimelineStatusEntity {
|
|||
contentShowing = false,
|
||||
pinned = false,
|
||||
card = null,
|
||||
repliesCount = 0
|
||||
repliesCount = 0,
|
||||
language = null,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -141,7 +142,8 @@ fun Status.toEntity(
|
|||
contentCollapsed = contentCollapsed,
|
||||
pinned = actionableStatus.pinned == true,
|
||||
card = actionableStatus.card?.let(gson::toJson),
|
||||
repliesCount = actionableStatus.repliesCount
|
||||
repliesCount = actionableStatus.repliesCount,
|
||||
language = actionableStatus.language,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -185,7 +187,8 @@ fun TimelineStatusWithAccount.toViewData(gson: Gson): StatusViewData {
|
|||
muted = status.muted,
|
||||
poll = poll,
|
||||
card = card,
|
||||
repliesCount = status.repliesCount
|
||||
repliesCount = status.repliesCount,
|
||||
language = status.language,
|
||||
)
|
||||
}
|
||||
val status = if (reblog != null) {
|
||||
|
@ -216,6 +219,7 @@ fun TimelineStatusWithAccount.toViewData(gson: Gson): StatusViewData {
|
|||
poll = null,
|
||||
card = null,
|
||||
repliesCount = status.repliesCount,
|
||||
language = status.language,
|
||||
)
|
||||
} else {
|
||||
Status(
|
||||
|
@ -245,6 +249,7 @@ fun TimelineStatusWithAccount.toViewData(gson: Gson): StatusViewData {
|
|||
poll = poll,
|
||||
card = card,
|
||||
repliesCount = status.repliesCount,
|
||||
language = status.language,
|
||||
)
|
||||
}
|
||||
return StatusViewData.Concrete(
|
||||
|
|
|
@ -31,7 +31,7 @@ import java.io.File;
|
|||
*/
|
||||
@Database(entities = { DraftEntity.class, AccountEntity.class, InstanceEntity.class, TimelineStatusEntity.class,
|
||||
TimelineAccountEntity.class, ConversationEntity.class
|
||||
}, version = 41)
|
||||
}, version = 42)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
public abstract AccountDao accountDao();
|
||||
|
@ -601,4 +601,13 @@ public abstract class AppDatabase extends RoomDatabase {
|
|||
database.execSQL("ALTER TABLE `DraftEntity` ADD COLUMN `scheduledAt` TEXT");
|
||||
}
|
||||
};
|
||||
|
||||
public static final Migration MIGRATION_41_42 = new Migration(41, 42) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
database.execSQL("ALTER TABLE `DraftEntity` ADD COLUMN `language` TEXT");
|
||||
database.execSQL("ALTER TABLE `TimelineStatusEntity` ADD COLUMN `language` TEXT");
|
||||
database.execSQL("ALTER TABLE `ConversationEntity` ADD COLUMN `s_language` TEXT");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ data class DraftEntity(
|
|||
val poll: NewPoll?,
|
||||
val failedToSend: Boolean,
|
||||
val scheduledAt: String?,
|
||||
val language: String?,
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
|
@ -81,6 +81,7 @@ data class TimelineStatusEntity(
|
|||
val contentShowing: Boolean,
|
||||
val pinned: Boolean,
|
||||
val card: String?,
|
||||
val language: String?,
|
||||
)
|
||||
|
||||
@Entity(
|
||||
|
|
|
@ -66,6 +66,7 @@ class AppModule {
|
|||
AppDatabase.MIGRATION_32_33, AppDatabase.MIGRATION_33_34, AppDatabase.MIGRATION_34_35,
|
||||
AppDatabase.MIGRATION_35_36, AppDatabase.MIGRATION_36_37, AppDatabase.MIGRATION_37_38,
|
||||
AppDatabase.MIGRATION_38_39, AppDatabase.MIGRATION_39_40, AppDatabase.MIGRATION_40_41,
|
||||
AppDatabase.MIGRATION_41_42,
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -27,7 +27,8 @@ data class DeletedStatus(
|
|||
val sensitive: Boolean,
|
||||
@SerializedName("media_attachments") var attachments: ArrayList<Attachment>?,
|
||||
val poll: Poll?,
|
||||
@SerializedName("created_at") val createdAt: Date
|
||||
@SerializedName("created_at") val createdAt: Date,
|
||||
val language: String?,
|
||||
) {
|
||||
fun isEmpty(): Boolean {
|
||||
return text == null && attachments == null
|
||||
|
|
|
@ -27,7 +27,8 @@ data class NewStatus(
|
|||
val sensitive: Boolean,
|
||||
@SerializedName("media_ids") val mediaIds: List<String>?,
|
||||
@SerializedName("scheduled_at") val scheduledAt: String?,
|
||||
val poll: NewPoll?
|
||||
val poll: NewPoll?,
|
||||
val language: String?,
|
||||
)
|
||||
|
||||
@Parcelize
|
||||
|
|
|
@ -48,7 +48,8 @@ data class Status(
|
|||
val pinned: Boolean?,
|
||||
val muted: Boolean?,
|
||||
val poll: Poll?,
|
||||
val card: Card?
|
||||
val card: Card?,
|
||||
val language: String?,
|
||||
) {
|
||||
|
||||
val actionableId: String
|
||||
|
@ -130,7 +131,8 @@ data class Status(
|
|||
sensitive = sensitive,
|
||||
attachments = attachments,
|
||||
poll = poll,
|
||||
createdAt = createdAt
|
||||
createdAt = createdAt,
|
||||
language = language,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ public abstract class SFragment extends Fragment implements Injectable {
|
|||
composeOptions.setMentionedUsernames(mentionedUsernames);
|
||||
composeOptions.setReplyingStatusAuthor(actionableStatus.getAccount().getLocalUsername());
|
||||
composeOptions.setReplyingStatusContent(parseAsMastodonHtml(actionableStatus.getContent()).toString());
|
||||
composeOptions.setLanguage(actionableStatus.getLanguage());
|
||||
|
||||
Intent intent = ComposeActivity.startIntent(getContext(), composeOptions);
|
||||
getActivity().startActivity(intent);
|
||||
|
@ -425,6 +426,7 @@ public abstract class SFragment extends Fragment implements Injectable {
|
|||
composeOptions.setMediaAttachments(deletedStatus.getAttachments());
|
||||
composeOptions.setSensitive(deletedStatus.getSensitive());
|
||||
composeOptions.setModifiedInitialState(true);
|
||||
composeOptions.setLanguage(deletedStatus.getLanguage());
|
||||
if (deletedStatus.getPoll() != null) {
|
||||
composeOptions.setPoll(deletedStatus.getPoll().toNewPoll(deletedStatus.getCreatedAt()));
|
||||
}
|
||||
|
|
|
@ -98,7 +98,8 @@ class SendStatusBroadcastReceiver : BroadcastReceiver() {
|
|||
draftId = -1,
|
||||
idempotencyKey = randomAlphanumericString(16),
|
||||
retries = 0,
|
||||
mediaProcessed = mutableListOf()
|
||||
mediaProcessed = mutableListOf(),
|
||||
null,
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -156,7 +156,8 @@ class SendStatusService : Service(), Injectable {
|
|||
statusToSend.sensitive,
|
||||
statusToSend.mediaIds,
|
||||
statusToSend.scheduledAt,
|
||||
statusToSend.poll
|
||||
statusToSend.poll,
|
||||
statusToSend.language,
|
||||
)
|
||||
|
||||
mastodonApi.createStatus(
|
||||
|
@ -259,7 +260,8 @@ class SendStatusService : Service(), Injectable {
|
|||
mediaDescriptions = status.mediaDescriptions,
|
||||
poll = status.poll,
|
||||
failedToSend = true,
|
||||
scheduledAt = status.scheduledAt
|
||||
scheduledAt = status.scheduledAt,
|
||||
language = status.language,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -366,5 +368,6 @@ data class StatusToSend(
|
|||
val draftId: Int,
|
||||
val idempotencyKey: String,
|
||||
var retries: Int,
|
||||
val mediaProcessed: MutableList<Boolean>
|
||||
val mediaProcessed: MutableList<Boolean>,
|
||||
val language: String?,
|
||||
) : Parcelable
|
||||
|
|
|
@ -22,6 +22,19 @@
|
|||
tools:ignore="ContentDescription" />
|
||||
<!--content description will be set in code -->
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/composePostLanguageButton"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:padding="0dp"
|
||||
android:contentDescription="@string/description_post_language"
|
||||
android:textColor="?android:attr/textColorTertiary"
|
||||
android:textSize="?attr/status_text_large"
|
||||
android:textStyle="bold"
|
||||
app:tooltipText="@string/description_post_language" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/atButton"
|
||||
style="@style/TuskyImageButton"
|
||||
|
|
|
@ -515,6 +515,7 @@
|
|||
<string name="description_poll">
|
||||
Poll with choices: %1$s, %2$s, %3$s, %4$s; %5$s
|
||||
</string>
|
||||
<string name="description_post_language">Post language</string>
|
||||
|
||||
<string name="hint_list_name">List name</string>
|
||||
|
||||
|
|
|
@ -88,7 +88,8 @@ class BottomSheetActivityTest {
|
|||
pinned = false,
|
||||
muted = false,
|
||||
poll = null,
|
||||
card = null
|
||||
card = null,
|
||||
language = null,
|
||||
)
|
||||
private val statusSingle = Single.just(SearchResult(emptyList(), listOf(status), emptyList()))
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.robolectric.Robolectric
|
|||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
import org.robolectric.fakes.RoboMenuItem
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Created by charlag on 3/7/18.
|
||||
|
@ -444,6 +445,19 @@ class ComposeActivityTest {
|
|||
assertEquals(selectionEnd + insertText.length, editor.selectionEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenNoLanguageIsGiven_defaultLanguageIsSelected() {
|
||||
assertEquals(Locale.getDefault().language, activity.selectedLanguage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun languageGivenInComposeOptionsIsRespected() {
|
||||
val language = "no"
|
||||
composeOptions = ComposeActivity.ComposeOptions(language = language)
|
||||
setupActivity()
|
||||
assertEquals(language, activity.selectedLanguage)
|
||||
}
|
||||
|
||||
private fun clickUp() {
|
||||
val menuItem = RoboMenuItem(android.R.id.home)
|
||||
activity.onOptionsItemSelected(menuItem)
|
||||
|
|
|
@ -260,7 +260,8 @@ class FilterTest {
|
|||
ownVotes = null
|
||||
)
|
||||
} else null,
|
||||
card = null
|
||||
card = null,
|
||||
language = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,8 @@ fun mockStatus(
|
|||
pinned = false,
|
||||
muted = false,
|
||||
poll = null,
|
||||
card = null
|
||||
card = null,
|
||||
language = null,
|
||||
)
|
||||
|
||||
fun mockStatusViewData(
|
||||
|
|
|
@ -463,6 +463,7 @@ class TimelineDaoTest {
|
|||
contentShowing = true,
|
||||
pinned = false,
|
||||
card = card,
|
||||
language = null,
|
||||
)
|
||||
return Triple(status, author, reblogAuthor)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue