Merge with upstream
This commit is contained in:
commit
3e7bfb4f39
|
@ -22,12 +22,14 @@ import android.widget.ImageView
|
|||
import com.bumptech.glide.Glide
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import java.util.*
|
||||
|
||||
class EmojiAdapter(emojiList: List<Emoji>, private val onEmojiSelectedListener: OnEmojiSelectedListener) : RecyclerView.Adapter<EmojiAdapter.EmojiHolder>() {
|
||||
private val emojiList : List<Emoji>
|
||||
|
||||
init {
|
||||
this.emojiList = emojiList.filter { emoji -> emoji.visibleInPicker == null || emoji.visibleInPicker }
|
||||
.sortedBy { it.shortcode.toLowerCase(Locale.ROOT) }
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
|
|
|
@ -199,7 +199,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
} else {
|
||||
if (payloadForHolder instanceof List)
|
||||
for (Object item : (List) payloadForHolder) {
|
||||
if (StatusBaseViewHolder.Key.KEY_CREATED.equals(item)) {
|
||||
if (StatusBaseViewHolder.Key.KEY_CREATED.equals(item) && statusViewData != null) {
|
||||
holder.setCreatedAt(statusViewData.getCreatedAt());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import android.net.Uri
|
|||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import androidx.preference.PreferenceManager
|
||||
import android.provider.MediaStore
|
||||
import android.provider.OpenableColumns
|
||||
import android.text.TextUtils
|
||||
|
@ -54,6 +53,7 @@ import androidx.core.view.isGone
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.transition.TransitionManager
|
||||
|
@ -66,6 +66,7 @@ import com.keylesspalace.tusky.adapter.ComposeAutoCompleteAdapter
|
|||
import com.keylesspalace.tusky.adapter.EmojiAdapter
|
||||
import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener
|
||||
import com.keylesspalace.tusky.components.compose.dialog.makeCaptionDialog
|
||||
import com.keylesspalace.tusky.components.compose.dialog.showAddPollDialog
|
||||
import com.keylesspalace.tusky.components.compose.view.ComposeOptionsListener
|
||||
import com.keylesspalace.tusky.db.AccountEntity
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
|
@ -75,7 +76,6 @@ import com.keylesspalace.tusky.entity.Emoji
|
|||
import com.keylesspalace.tusky.entity.NewPoll
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.util.*
|
||||
import com.keylesspalace.tusky.components.compose.dialog.showAddPollDialog
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
@ -170,8 +170,7 @@ class ComposeActivity : BaseActivity(),
|
|||
setupContentWarningField(composeOptions?.contentWarning)
|
||||
setupPollView()
|
||||
applyShareIntent(intent, savedInstanceState)
|
||||
|
||||
composeEditField.requestFocus()
|
||||
viewModel.setupComplete.value = true
|
||||
}
|
||||
|
||||
private fun uriToFilename(uri: Uri): String {
|
||||
|
@ -376,6 +375,10 @@ class ComposeActivity : BaseActivity(),
|
|||
viewModel.uploadError.observe {
|
||||
displayTransientError(R.string.error_media_upload_sending)
|
||||
}
|
||||
viewModel.setupComplete.observe {
|
||||
// Focus may have changed during view model setup, ensure initial focus is on the edit field
|
||||
composeEditField.requestFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -458,7 +461,11 @@ class ComposeActivity : BaseActivity(),
|
|||
// If you select "backward" in an editable, you get SelectionStart > SelectionEnd
|
||||
val start = composeEditField.selectionStart.coerceAtMost(composeEditField.selectionEnd)
|
||||
val end = composeEditField.selectionStart.coerceAtLeast(composeEditField.selectionEnd)
|
||||
composeEditField.text.replace(start, end, text)
|
||||
val textToInsert = if (
|
||||
composeEditField.text.isNotEmpty()
|
||||
&& !composeEditField.text[start - 1].isWhitespace()
|
||||
) " $text" else text
|
||||
composeEditField.text.replace(start, end, textToInsert)
|
||||
|
||||
// Set the cursor after the inserted text
|
||||
composeEditField.setSelection(start + text.length)
|
||||
|
@ -488,12 +495,53 @@ class ComposeActivity : BaseActivity(),
|
|||
boldButton.visibility = visibility
|
||||
}
|
||||
|
||||
fun prependSelectedWordsWith(text: CharSequence) {
|
||||
// If you select "backward" in an editable, you get SelectionStart > SelectionEnd
|
||||
val start = composeEditField.selectionStart.coerceAtMost(composeEditField.selectionEnd)
|
||||
val end = composeEditField.selectionStart.coerceAtLeast(composeEditField.selectionEnd)
|
||||
val editorText = composeEditField.text
|
||||
|
||||
if (start == end) {
|
||||
// No selection, just insert text at caret
|
||||
editorText.insert(start, text)
|
||||
// Set the cursor after the inserted text
|
||||
composeEditField.setSelection(start + text.length)
|
||||
} else {
|
||||
var wasWord: Boolean
|
||||
var isWord = end < editorText.length && !Character.isWhitespace(editorText[end])
|
||||
var newEnd = end
|
||||
|
||||
// Iterate the selection backward so we don't have to juggle indices on insertion
|
||||
var index = end - 1
|
||||
while (index >= start - 1 && index >= 0) {
|
||||
wasWord = isWord
|
||||
isWord = !Character.isWhitespace(editorText[index])
|
||||
if (wasWord && !isWord) {
|
||||
// We've reached the beginning of a word, perform insert
|
||||
editorText.insert(index + 1, text)
|
||||
newEnd += text.length
|
||||
}
|
||||
--index
|
||||
}
|
||||
|
||||
if (start == 0 && isWord) {
|
||||
// Special case when the selection includes the start of the text
|
||||
editorText.insert(0, text)
|
||||
newEnd += text.length
|
||||
}
|
||||
|
||||
// Keep the same text (including insertions) selected
|
||||
composeEditField.setSelection(start, newEnd)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun atButtonClicked() {
|
||||
replaceTextAtCaret("@")
|
||||
prependSelectedWordsWith("@")
|
||||
}
|
||||
|
||||
private fun hashButtonClicked() {
|
||||
replaceTextAtCaret("#")
|
||||
prependSelectedWordsWith("#")
|
||||
}
|
||||
|
||||
private fun codeButtonClicked() {
|
||||
|
|
|
@ -84,6 +84,7 @@ class ComposeViewModel
|
|||
|
||||
val statusVisibility = mutableLiveData(Status.Visibility.UNKNOWN)
|
||||
val showContentWarning = mutableLiveData(false)
|
||||
val setupComplete = mutableLiveData(false)
|
||||
val poll: MutableLiveData<NewPoll?> = mutableLiveData(null)
|
||||
val scheduledAt: MutableLiveData<String?> = mutableLiveData(null)
|
||||
|
||||
|
@ -374,6 +375,7 @@ class ComposeViewModel
|
|||
if (contentWarning != null) {
|
||||
startingContentWarning = contentWarning
|
||||
}
|
||||
showContentWarning.value = !contentWarning.isNullOrBlank()
|
||||
|
||||
// recreate media list
|
||||
// when coming from SavedTootActivity
|
||||
|
|
|
@ -78,7 +78,8 @@ class ReportActivity : BottomSheetActivity(), HasAndroidInjector {
|
|||
}
|
||||
|
||||
private fun initViewPager() {
|
||||
wizard.adapter = ReportPagerAdapter(supportFragmentManager)
|
||||
wizard.isUserInputEnabled = false
|
||||
wizard.adapter = ReportPagerAdapter(this)
|
||||
}
|
||||
|
||||
private fun subscribeObservables() {
|
||||
|
|
|
@ -16,14 +16,14 @@
|
|||
package com.keylesspalace.tusky.components.report.adapter
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentPagerAdapter
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.keylesspalace.tusky.components.report.fragments.ReportDoneFragment
|
||||
import com.keylesspalace.tusky.components.report.fragments.ReportNoteFragment
|
||||
import com.keylesspalace.tusky.components.report.fragments.ReportStatusesFragment
|
||||
|
||||
class ReportPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manager) {
|
||||
override fun getItem(position: Int): Fragment {
|
||||
class ReportPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
return when (position) {
|
||||
0 -> ReportStatusesFragment.newInstance()
|
||||
1 -> ReportNoteFragment.newInstance()
|
||||
|
@ -32,5 +32,5 @@ class ReportPagerAdapter(manager: FragmentManager) : FragmentPagerAdapter(manage
|
|||
}
|
||||
}
|
||||
|
||||
override fun getCount(): Int = 3
|
||||
override fun getItemCount() = 3
|
||||
}
|
|
@ -28,13 +28,12 @@ import com.keylesspalace.tusky.BottomSheetActivity
|
|||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.components.search.adapter.SearchPagerAdapter
|
||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.DispatchingAndroidInjector
|
||||
import dagger.android.HasAndroidInjector
|
||||
import kotlinx.android.synthetic.main.activity_search.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class SearchActivity : BottomSheetActivity(), SearchView.OnQueryTextListener, HasAndroidInjector {
|
||||
class SearchActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||
@Inject
|
||||
lateinit var androidInjector: DispatchingAndroidInjector<Any>
|
||||
|
||||
|
@ -94,14 +93,6 @@ class SearchActivity : BottomSheetActivity(), SearchView.OnQueryTextListener, Ha
|
|||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getPageTitle(position: Int): CharSequence? {
|
||||
return when (position) {
|
||||
0 -> getString(R.string.title_statuses)
|
||||
|
@ -123,15 +114,12 @@ class SearchActivity : BottomSheetActivity(), SearchView.OnQueryTextListener, Ha
|
|||
|
||||
searchView.setSearchableInfo((getSystemService(Context.SEARCH_SERVICE) as? SearchManager)?.getSearchableInfo(componentName))
|
||||
|
||||
searchView.setOnQueryTextListener(this)
|
||||
searchView.requestFocus()
|
||||
|
||||
searchView.maxWidth = Integer.MAX_VALUE
|
||||
}
|
||||
|
||||
override fun androidInjector(): AndroidInjector<Any>? {
|
||||
return androidInjector
|
||||
}
|
||||
override fun androidInjector() = androidInjector
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
|
|
|
@ -3,18 +3,15 @@ package com.keylesspalace.tusky.components.search
|
|||
import android.util.Log
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import androidx.paging.PagedList
|
||||
import com.keylesspalace.tusky.components.search.adapter.SearchRepository
|
||||
import com.keylesspalace.tusky.db.AccountEntity
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.entity.*
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.network.TimelineCases
|
||||
import com.keylesspalace.tusky.util.Listing
|
||||
import com.keylesspalace.tusky.util.NetworkState
|
||||
import com.keylesspalace.tusky.util.RxAwareViewModel
|
||||
import com.keylesspalace.tusky.util.ViewDataUtils
|
||||
import com.keylesspalace.tusky.util.*
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
|
@ -23,7 +20,8 @@ import javax.inject.Inject
|
|||
class SearchViewModel @Inject constructor(
|
||||
mastodonApi: MastodonApi,
|
||||
private val timelineCases: TimelineCases,
|
||||
private val accountManager: AccountManager) : RxAwareViewModel() {
|
||||
private val accountManager: AccountManager
|
||||
) : RxAwareViewModel() {
|
||||
|
||||
var currentQuery: String = ""
|
||||
|
||||
|
@ -33,49 +31,46 @@ class SearchViewModel @Inject constructor(
|
|||
accountManager.activeAccount = value
|
||||
}
|
||||
|
||||
val mediaPreviewEnabled: Boolean
|
||||
get() = activeAccount?.mediaPreviewEnabled ?: false
|
||||
val mediaPreviewEnabled = activeAccount?.mediaPreviewEnabled ?: false
|
||||
val alwaysShowSensitiveMedia = activeAccount?.alwaysShowSensitiveMedia ?: false
|
||||
val alwaysOpenSpoiler = activeAccount?.alwaysOpenSpoiler ?: false
|
||||
|
||||
private val statusesRepository = SearchRepository<Pair<Status, StatusViewData.Concrete>>(mastodonApi)
|
||||
private val accountsRepository = SearchRepository<Account>(mastodonApi)
|
||||
private val hashtagsRepository = SearchRepository<HashTag>(mastodonApi)
|
||||
val alwaysShowSensitiveMedia: Boolean = activeAccount?.alwaysShowSensitiveMedia
|
||||
?: false
|
||||
val alwaysOpenSpoiler: Boolean = activeAccount?.alwaysOpenSpoiler
|
||||
?: false
|
||||
|
||||
private val repoResultStatus = MutableLiveData<Listing<Pair<Status, StatusViewData.Concrete>>>()
|
||||
val statuses: LiveData<PagedList<Pair<Status, StatusViewData.Concrete>>> = Transformations.switchMap(repoResultStatus) { it.pagedList }
|
||||
val networkStateStatus: LiveData<NetworkState> = Transformations.switchMap(repoResultStatus) { it.networkState }
|
||||
val networkStateStatusRefresh: LiveData<NetworkState> = Transformations.switchMap(repoResultStatus) { it.refreshState }
|
||||
val statuses: LiveData<PagedList<Pair<Status, StatusViewData.Concrete>>> = repoResultStatus.switchMap { it.pagedList }
|
||||
val networkStateStatus: LiveData<NetworkState> = repoResultStatus.switchMap { it.networkState }
|
||||
val networkStateStatusRefresh: LiveData<NetworkState> = repoResultStatus.switchMap { it.refreshState }
|
||||
|
||||
private val repoResultAccount = MutableLiveData<Listing<Account>>()
|
||||
val accounts: LiveData<PagedList<Account>> = Transformations.switchMap(repoResultAccount) { it.pagedList }
|
||||
val networkStateAccount: LiveData<NetworkState> = Transformations.switchMap(repoResultAccount) { it.networkState }
|
||||
val networkStateAccountRefresh: LiveData<NetworkState> = Transformations.switchMap(repoResultAccount) { it.refreshState }
|
||||
val accounts: LiveData<PagedList<Account>> = repoResultAccount.switchMap { it.pagedList }
|
||||
val networkStateAccount: LiveData<NetworkState> = repoResultAccount.switchMap { it.networkState }
|
||||
val networkStateAccountRefresh: LiveData<NetworkState> = repoResultAccount.switchMap { it.refreshState }
|
||||
|
||||
private val repoResultHashTag = MutableLiveData<Listing<HashTag>>()
|
||||
val hashtags: LiveData<PagedList<HashTag>> = Transformations.switchMap(repoResultHashTag) { it.pagedList }
|
||||
val networkStateHashTag: LiveData<NetworkState> = Transformations.switchMap(repoResultHashTag) { it.networkState }
|
||||
val networkStateHashTagRefresh: LiveData<NetworkState> = Transformations.switchMap(repoResultHashTag) { it.refreshState }
|
||||
val hashtags: LiveData<PagedList<HashTag>> = repoResultHashTag.switchMap { it.pagedList }
|
||||
val networkStateHashTag: LiveData<NetworkState> = repoResultHashTag.switchMap { it.networkState }
|
||||
val networkStateHashTagRefresh: LiveData<NetworkState> = repoResultHashTag.switchMap { it.refreshState }
|
||||
|
||||
private val loadedStatuses = ArrayList<Pair<Status, StatusViewData.Concrete>>()
|
||||
fun search(query: String) {
|
||||
loadedStatuses.clear()
|
||||
repoResultStatus.value = statusesRepository.getSearchData(SearchType.Status, query, disposables, initialItems = loadedStatuses) {
|
||||
(it?.statuses?.map { status -> Pair(status, ViewDataUtils.statusToViewData(status, alwaysShowSensitiveMedia, alwaysOpenSpoiler)!!) }
|
||||
?: emptyList())
|
||||
it?.statuses?.map { status -> Pair(status, ViewDataUtils.statusToViewData(status, alwaysShowSensitiveMedia, alwaysOpenSpoiler)!!) }
|
||||
.orEmpty()
|
||||
.apply {
|
||||
loadedStatuses.addAll(this)
|
||||
}
|
||||
}
|
||||
repoResultAccount.value = accountsRepository.getSearchData(SearchType.Account, query, disposables) {
|
||||
it?.accounts ?: emptyList()
|
||||
it?.accounts.orEmpty()
|
||||
}
|
||||
val hashtagQuery = if (query.startsWith("#")) query else "#$query"
|
||||
repoResultHashTag.value =
|
||||
hashtagsRepository.getSearchData(SearchType.Hashtag, hashtagQuery, disposables) {
|
||||
it?.hashtags ?: emptyList()
|
||||
it?.hashtags.orEmpty()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -184,11 +179,11 @@ class SearchViewModel @Inject constructor(
|
|||
fun bookmark(status: Pair<Status, StatusViewData.Concrete>, isBookmarked: Boolean) {
|
||||
val idx = loadedStatuses.indexOf(status)
|
||||
if (idx >= 0) {
|
||||
val newPair = Pair(status.first, StatusViewData.Builder(status.second).setFavourited(isBookmarked).createStatusViewData())
|
||||
val newPair = Pair(status.first, StatusViewData.Builder(status.second).setBookmarked(isBookmarked).createStatusViewData())
|
||||
loadedStatuses[idx] = newPair
|
||||
repoResultStatus.value?.refresh?.invoke()
|
||||
}
|
||||
timelineCases.favourite(status.first, isBookmarked)
|
||||
timelineCases.bookmark(status.first, isBookmarked)
|
||||
.onErrorReturnItem(status.first)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
|
|
|
@ -26,8 +26,7 @@ import com.keylesspalace.tusky.entity.Account
|
|||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
|
||||
class SearchAccountsAdapter(private val linkListener: LinkListener)
|
||||
: PagedListAdapter<Account, RecyclerView.ViewHolder>(STATUS_COMPARATOR) {
|
||||
|
||||
: PagedListAdapter<Account, RecyclerView.ViewHolder>(ACCOUNT_COMPARATOR) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
|
@ -37,21 +36,16 @@ class SearchAccountsAdapter(private val linkListener: LinkListener)
|
|||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
getItem(position)?.let { item ->
|
||||
(holder as? AccountViewHolder)?.apply {
|
||||
(holder as AccountViewHolder).apply {
|
||||
setupWithAccount(item)
|
||||
setupLinkListener(linkListener)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override fun getItem(position: Int): Account? {
|
||||
return super.getItem(position)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val STATUS_COMPARATOR = object : DiffUtil.ItemCallback<Account>() {
|
||||
val ACCOUNT_COMPARATOR = object : DiffUtil.ItemCallback<Account>() {
|
||||
override fun areContentsTheSame(oldItem: Account, newItem: Account): Boolean =
|
||||
oldItem.deepEquals(newItem)
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
package com.keylesspalace.tusky.components.search.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.paging.PositionalDataSource
|
||||
import com.keylesspalace.tusky.components.search.SearchType
|
||||
|
@ -23,16 +22,18 @@ import com.keylesspalace.tusky.entity.SearchResult
|
|||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.NetworkState
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.addTo
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
class SearchDataSource<T>(
|
||||
private val mastodonApi: MastodonApi,
|
||||
private val searchType: SearchType,
|
||||
private val searchRequest: String?,
|
||||
private val searchRequest: String,
|
||||
private val disposables: CompositeDisposable,
|
||||
private val retryExecutor: Executor,
|
||||
private val initialItems: List<T>? = null,
|
||||
private val parser: (SearchResult?) -> List<T>) : PositionalDataSource<T>() {
|
||||
private val parser: (SearchResult?) -> List<T>,
|
||||
private val source: SearchDataSourceFactory<T>) : PositionalDataSource<T>() {
|
||||
|
||||
val networkState = MutableLiveData<NetworkState>()
|
||||
|
||||
|
@ -48,24 +49,20 @@ class SearchDataSource<T>(
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<T>) {
|
||||
if (!initialItems.isNullOrEmpty()) {
|
||||
callback.onResult(initialItems, 0)
|
||||
callback.onResult(initialItems.toList(), 0)
|
||||
} else {
|
||||
networkState.postValue(NetworkState.LOADED)
|
||||
retry = null
|
||||
initialLoad.postValue(NetworkState.LOADING)
|
||||
mastodonApi.searchObservable(
|
||||
query = searchRequest ?: "",
|
||||
query = searchRequest,
|
||||
type = searchType.apiParameter,
|
||||
resolve = true,
|
||||
limit = params.requestedLoadSize,
|
||||
offset = 0,
|
||||
following =false)
|
||||
.doOnSubscribe {
|
||||
disposables.add(it)
|
||||
}
|
||||
.subscribe(
|
||||
{ data ->
|
||||
val res = parser(data)
|
||||
|
@ -79,19 +76,18 @@ class SearchDataSource<T>(
|
|||
}
|
||||
initialLoad.postValue(NetworkState.error(error.message))
|
||||
}
|
||||
)
|
||||
).addTo(disposables)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<T>) {
|
||||
networkState.postValue(NetworkState.LOADING)
|
||||
retry = null
|
||||
if(source.exhausted) {
|
||||
return callback.onResult(emptyList())
|
||||
}
|
||||
mastodonApi.searchObservable(searchType.apiParameter, searchRequest, true, params.loadSize, params.startPosition, false)
|
||||
.doOnSubscribe {
|
||||
disposables.add(it)
|
||||
}
|
||||
.subscribe(
|
||||
{ data ->
|
||||
// Working around Mastodon bug where exact match is returned no matter
|
||||
|
@ -105,9 +101,11 @@ class SearchDataSource<T>(
|
|||
} else {
|
||||
parser(data)
|
||||
}
|
||||
if(res.isEmpty()) {
|
||||
source.exhausted = true
|
||||
}
|
||||
callback.onResult(res)
|
||||
networkState.postValue(NetworkState.LOADED)
|
||||
|
||||
},
|
||||
{ error ->
|
||||
retry = {
|
||||
|
@ -115,7 +113,7 @@ class SearchDataSource<T>(
|
|||
}
|
||||
networkState.postValue(NetworkState.error(error.message))
|
||||
}
|
||||
)
|
||||
).addTo(disposables)
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -26,14 +26,18 @@ import java.util.concurrent.Executor
|
|||
class SearchDataSourceFactory<T>(
|
||||
private val mastodonApi: MastodonApi,
|
||||
private val searchType: SearchType,
|
||||
private val searchRequest: String?,
|
||||
private val searchRequest: String,
|
||||
private val disposables: CompositeDisposable,
|
||||
private val retryExecutor: Executor,
|
||||
private val cacheData: List<T>? = null,
|
||||
private val parser: (SearchResult?) -> List<T>) : DataSource.Factory<Int, T>() {
|
||||
|
||||
val sourceLiveData = MutableLiveData<SearchDataSource<T>>()
|
||||
|
||||
var exhausted = false
|
||||
|
||||
override fun create(): DataSource<Int, T> {
|
||||
val source = SearchDataSource(mastodonApi, searchType, searchRequest, disposables, retryExecutor, cacheData, parser)
|
||||
val source = SearchDataSource(mastodonApi, searchType, searchRequest, disposables, retryExecutor, cacheData, parser, this)
|
||||
sourceLiveData.postValue(source)
|
||||
return source
|
||||
}
|
||||
|
|
|
@ -26,8 +26,7 @@ import com.keylesspalace.tusky.entity.HashTag
|
|||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
|
||||
class SearchHashtagsAdapter(private val linkListener: LinkListener)
|
||||
: PagedListAdapter<HashTag, RecyclerView.ViewHolder>(STATUS_COMPARATOR) {
|
||||
|
||||
: PagedListAdapter<HashTag, RecyclerView.ViewHolder>(HASHTAG_COMPARATOR) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
|
@ -36,17 +35,14 @@ class SearchHashtagsAdapter(private val linkListener: LinkListener)
|
|||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
getItem(position)?.let { item ->
|
||||
(holder as? HashtagViewHolder)?.apply {
|
||||
setup(item.name, linkListener)
|
||||
}
|
||||
getItem(position)?.let { (name) ->
|
||||
(holder as HashtagViewHolder).setup(name, linkListener)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val STATUS_COMPARATOR = object : DiffUtil.ItemCallback<HashTag>() {
|
||||
val HASHTAG_COMPARATOR = object : DiffUtil.ItemCallback<HashTag>() {
|
||||
override fun areContentsTheSame(oldItem: HashTag, newItem: HashTag): Boolean =
|
||||
oldItem.name == newItem.name
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class SearchRepository<T>(private val mastodonApi: MastodonApi) {
|
|||
|
||||
private val executor = Executors.newSingleThreadExecutor()
|
||||
|
||||
fun getSearchData(searchType: SearchType, searchRequest: String?, disposables: CompositeDisposable, pageSize: Int = 20,
|
||||
fun getSearchData(searchType: SearchType, searchRequest: String, disposables: CompositeDisposable, pageSize: Int = 20,
|
||||
initialItems: List<T>? = null, parser: (SearchResult?) -> List<T>): Listing<T> {
|
||||
val sourceFactory = SearchDataSourceFactory(mastodonApi, searchType, searchRequest, disposables, executor, initialItems, parser)
|
||||
val livePagedList = sourceFactory.toLiveData(
|
||||
|
|
|
@ -32,7 +32,6 @@ class SearchStatusesAdapter(
|
|||
private val statusListener: StatusActionListener
|
||||
) : PagedListAdapter<Pair<Status, StatusViewData.Concrete>, RecyclerView.ViewHolder>(STATUS_COMPARATOR) {
|
||||
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_status, parent, false)
|
||||
|
@ -41,8 +40,7 @@ class SearchStatusesAdapter(
|
|||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
getItem(position)?.let { item ->
|
||||
(holder as? StatusViewHolder)?.setupWithStatus(item.second, statusListener,
|
||||
statusDisplayOptions)
|
||||
(holder as StatusViewHolder).setupWithStatus(item.second, statusListener, statusDisplayOptions)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import androidx.paging.PagedList
|
|||
import androidx.paging.PagedListAdapter
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.keylesspalace.tusky.AccountActivity
|
||||
|
@ -62,8 +63,8 @@ abstract class SearchFragment<T> : Fragment(),
|
|||
swipeRefreshLayout.setOnRefreshListener(this)
|
||||
swipeRefreshLayout.setColorSchemeResources(R.color.tusky_blue)
|
||||
swipeRefreshLayout.setProgressBackgroundColorSchemeColor(
|
||||
ThemeUtils.getColor(swipeRefreshLayout.context, android.R.attr.colorBackground))
|
||||
|
||||
ThemeUtils.getColor(swipeRefreshLayout.context, android.R.attr.colorBackground)
|
||||
)
|
||||
}
|
||||
|
||||
private fun subscribeObservables() {
|
||||
|
@ -75,8 +76,9 @@ abstract class SearchFragment<T> : Fragment(),
|
|||
|
||||
searchProgressBar.visible(it == NetworkState.LOADING)
|
||||
|
||||
if (it.status == Status.FAILED)
|
||||
showError(it.msg)
|
||||
if (it.status == Status.FAILED) {
|
||||
showError()
|
||||
}
|
||||
checkNoData()
|
||||
|
||||
})
|
||||
|
@ -85,8 +87,9 @@ abstract class SearchFragment<T> : Fragment(),
|
|||
|
||||
progressBarBottom.visible(it == NetworkState.LOADING)
|
||||
|
||||
if (it.status == Status.FAILED)
|
||||
showError(it.msg)
|
||||
if (it.status == Status.FAILED) {
|
||||
showError()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -99,7 +102,8 @@ abstract class SearchFragment<T> : Fragment(),
|
|||
searchRecyclerView.layoutManager = LinearLayoutManager(searchRecyclerView.context)
|
||||
adapter = createAdapter()
|
||||
searchRecyclerView.adapter = adapter
|
||||
|
||||
searchRecyclerView.setHasFixedSize(true)
|
||||
(searchRecyclerView.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
|
||||
}
|
||||
|
||||
private fun showNoData(isEmpty: Boolean) {
|
||||
|
@ -109,7 +113,7 @@ abstract class SearchFragment<T> : Fragment(),
|
|||
searchNoResultsText.hide()
|
||||
}
|
||||
|
||||
private fun showError(@Suppress("UNUSED_PARAMETER") msg: String?) {
|
||||
private fun showError() {
|
||||
if (snackbarErrorRetry?.isShown != true) {
|
||||
snackbarErrorRetry = Snackbar.make(layoutRoot, R.string.failed_search, Snackbar.LENGTH_INDEFINITE)
|
||||
snackbarErrorRetry?.setAction(R.string.action_retry) {
|
||||
|
@ -129,13 +133,12 @@ abstract class SearchFragment<T> : Fragment(),
|
|||
}
|
||||
|
||||
protected val bottomSheetActivity
|
||||
get() = (activity as? BottomSheetActivity)
|
||||
get() = (activity as? BottomSheetActivity)
|
||||
|
||||
override fun onRefresh() {
|
||||
|
||||
// Dismissed here because the RecyclerView bottomProgressBar is shown as soon as the retry begins.
|
||||
swipeRefreshLayout.post {
|
||||
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
viewModel.retryAllSearches()
|
||||
|
|
|
@ -59,7 +59,6 @@ import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from
|
|||
import com.uber.autodispose.autoDispose
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.android.synthetic.main.fragment_search.*
|
||||
import java.util.*
|
||||
|
||||
class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concrete>>(), StatusActionListener {
|
||||
|
||||
|
@ -70,6 +69,9 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
override val data: LiveData<PagedList<Pair<Status, StatusViewData.Concrete>>>
|
||||
get() = viewModel.statuses
|
||||
|
||||
private val searchAdapter
|
||||
get() = super.adapter as SearchStatusesAdapter
|
||||
|
||||
override fun createAdapter(): PagedListAdapter<Pair<Status, StatusViewData.Concrete>, *> {
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(searchRecyclerView.context)
|
||||
val statusDisplayOptions = StatusDisplayOptions(
|
||||
|
@ -87,37 +89,37 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
|
||||
|
||||
override fun onContentHiddenChange(isShowing: Boolean, position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.let {
|
||||
searchAdapter.getItem(position)?.let {
|
||||
viewModel.contentHiddenChange(it, isShowing)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReply(position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.first?.let { status ->
|
||||
searchAdapter.getItem(position)?.first?.let { status ->
|
||||
reply(status)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFavourite(favourite: Boolean, position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.let { status ->
|
||||
searchAdapter.getItem(position)?.let { status ->
|
||||
viewModel.favorite(status, favourite)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBookmark(bookmark: Boolean, position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.let { status ->
|
||||
searchAdapter.getItem(position)?.let { status ->
|
||||
viewModel.bookmark(status, bookmark)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMore(view: View, position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.first?.let {
|
||||
searchAdapter.getItem(position)?.first?.let {
|
||||
more(it, view, position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewMedia(position: Int, attachmentIndex: Int, view: View?) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.first?.actionableStatus?.let { actionable ->
|
||||
searchAdapter.getItem(position)?.first?.actionableStatus?.let { actionable ->
|
||||
when (actionable.attachments[attachmentIndex].type) {
|
||||
Attachment.Type.GIFV, Attachment.Type.VIDEO, Attachment.Type.IMAGE, Attachment.Type.AUDIO -> {
|
||||
val attachments = AttachmentViewData.list(actionable)
|
||||
|
@ -142,48 +144,48 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
}
|
||||
|
||||
override fun onViewThread(position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.first?.let { status ->
|
||||
searchAdapter.getItem(position)?.first?.let { status ->
|
||||
val actionableStatus = status.actionableStatus
|
||||
bottomSheetActivity?.viewThread(actionableStatus.id, actionableStatus.url)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOpenReblog(position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.first?.let { status ->
|
||||
searchAdapter.getItem(position)?.first?.let { status ->
|
||||
bottomSheetActivity?.viewAccount(status.account.id)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onExpandedChange(expanded: Boolean, position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.let {
|
||||
searchAdapter.getItem(position)?.let {
|
||||
viewModel.expandedChange(it, expanded)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoadMore(position: Int) {
|
||||
//Ignore
|
||||
// Not possible here
|
||||
}
|
||||
|
||||
override fun onContentCollapsedChange(isCollapsed: Boolean, position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.let {
|
||||
searchAdapter.getItem(position)?.let {
|
||||
viewModel.collapsedChange(it, isCollapsed)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onVoteInPoll(position: Int, choices: MutableList<Int>) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.let {
|
||||
searchAdapter.getItem(position)?.let {
|
||||
viewModel.voteInPoll(it, choices)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeItem(position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.let {
|
||||
searchAdapter.getItem(position)?.let {
|
||||
viewModel.removeItem(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReblog(reblog: Boolean, position: Int) {
|
||||
(adapter as? SearchStatusesAdapter)?.getItem(position)?.let { status ->
|
||||
searchAdapter.getItem(position)?.let { status ->
|
||||
viewModel.reblog(status, reblog)
|
||||
}
|
||||
}
|
||||
|
@ -193,27 +195,23 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
}
|
||||
|
||||
private fun reply(status: Status) {
|
||||
val inReplyToId = status.actionableId
|
||||
val actionableStatus = status.actionableStatus
|
||||
val replyVisibility = actionableStatus.visibility
|
||||
val contentWarning = actionableStatus.spoilerText
|
||||
val mentions = actionableStatus.mentions
|
||||
val mentionedUsernames = LinkedHashSet<String>()
|
||||
mentionedUsernames.add(actionableStatus.account.username)
|
||||
val loggedInUsername = viewModel.activeAccount?.username
|
||||
for ((_, _, username) in mentions) {
|
||||
mentionedUsernames.add(username)
|
||||
}
|
||||
mentionedUsernames.remove(loggedInUsername)
|
||||
val intent = ComposeActivity.startIntent(context!!, ComposeOptions(
|
||||
inReplyToId = inReplyToId,
|
||||
replyVisibility = replyVisibility,
|
||||
contentWarning = contentWarning,
|
||||
val mentionedUsernames = actionableStatus.mentions.map { it.username }
|
||||
.toMutableSet()
|
||||
.apply {
|
||||
add(actionableStatus.account.username)
|
||||
remove(viewModel.activeAccount?.username)
|
||||
}
|
||||
|
||||
val intent = ComposeActivity.startIntent(requireContext(), ComposeOptions(
|
||||
inReplyToId = status.actionableId,
|
||||
replyVisibility = actionableStatus.visibility,
|
||||
contentWarning = actionableStatus.spoilerText,
|
||||
mentionedUsernames = mentionedUsernames,
|
||||
replyingStatusAuthor = actionableStatus.account.localUsername,
|
||||
replyingStatusContent = actionableStatus.content.toString()
|
||||
))
|
||||
requireActivity().startActivity(intent)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private fun more(status: Status, view: View, position: Int) {
|
||||
|
@ -252,8 +250,7 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
}
|
||||
}
|
||||
|
||||
val menu = popup.menu
|
||||
val openAsItem = menu.findItem(R.id.status_open_as)
|
||||
val openAsItem = popup.menu.findItem(R.id.status_open_as)
|
||||
when (accounts.size) {
|
||||
0, 1 -> openAsItem.isVisible = false
|
||||
2 -> for (account in accounts) {
|
||||
|
@ -269,13 +266,12 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
popup.setOnMenuItemClickListener { item ->
|
||||
when (item.itemId) {
|
||||
R.id.status_share_content -> {
|
||||
var statusToShare: Status? = status
|
||||
if (statusToShare!!.reblog != null) statusToShare = statusToShare.reblog
|
||||
val statusToShare: Status = status.actionableStatus
|
||||
|
||||
val sendIntent = Intent()
|
||||
sendIntent.action = Intent.ACTION_SEND
|
||||
|
||||
val stringToShare = statusToShare!!.account.username +
|
||||
val stringToShare = statusToShare.account.username +
|
||||
" - " +
|
||||
statusToShare.content.toString()
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, stringToShare)
|
||||
|
@ -292,7 +288,7 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
R.id.status_copy_link -> {
|
||||
val clipboard = activity!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clipboard = requireActivity().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText(null, statusUrl))
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
|
@ -365,7 +361,7 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
val uri = Uri.parse(url)
|
||||
val filename = uri.lastPathSegment
|
||||
|
||||
val downloadManager = activity!!.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||
val downloadManager = requireActivity().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||
val request = DownloadManager.Request(uri)
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename)
|
||||
downloadManager.enqueue(request)
|
||||
|
@ -417,7 +413,7 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
deletedStatus
|
||||
}
|
||||
|
||||
val intent = ComposeActivity.startIntent(context!!, ComposeOptions(
|
||||
val intent = ComposeActivity.startIntent(requireContext(), ComposeOptions(
|
||||
tootText = redraftStatus.text ?: "",
|
||||
inReplyToId = redraftStatus.inReplyToId,
|
||||
visibility = redraftStatus.visibility,
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/* Copyright 2019 Joel Pyska
|
||||
*
|
||||
* 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.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
|
||||
class NoSwipeViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : ViewPager(context, attrs) {
|
||||
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<include layout="@layout/toolbar_basic" />
|
||||
|
||||
<com.keylesspalace.tusky.view.NoSwipeViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/wizard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
|
@ -235,7 +235,6 @@
|
|||
<string name="status_media_images">صور</string>
|
||||
<string name="status_media_video">فيديو</string>
|
||||
<string name="state_follow_requested">طلب متابعة</string>
|
||||
<string name="no_content">ليس هناك محتوى</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">في %dy</string>
|
||||
<string name="abbreviated_in_days">في %dd</string>
|
||||
|
@ -498,4 +497,7 @@
|
|||
<string name="list">القائمة</string>
|
||||
<string name="gradient_for_media">اظهر ألوانا متدرّجة للوسائط المخفية</string>
|
||||
|
||||
</resources>
|
||||
<string name="no_saved_status">ليس لديك أية مسودات.</string>
|
||||
<string name="no_scheduled_status">ليس لديك أية منشورات مُبرمَجة للنشر.</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -282,8 +282,6 @@
|
|||
|
||||
<string name="state_follow_requested">অনুরোধ অনুসরণ করুন</string>
|
||||
|
||||
<string name="no_content">কোন উপাদান নেই</string>
|
||||
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%dy এ</string>
|
||||
<string name="abbreviated_in_days">%dd এ</string>
|
||||
|
|
|
@ -203,8 +203,6 @@
|
|||
<string name="status_media_images">Imatges</string>
|
||||
<string name="status_media_video">Vídeo</string>
|
||||
|
||||
<string name="no_content">no hi ha cap contingut</string>
|
||||
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">en %d anys</string>
|
||||
<string name="abbreviated_in_days">en %dd</string>
|
||||
|
|
|
@ -245,7 +245,6 @@
|
|||
<string name="status_media_images">Obrázky</string>
|
||||
<string name="status_media_video">Video</string>
|
||||
<string name="state_follow_requested">Vyžádáno sledování</string>
|
||||
<string name="no_content">žádný obsah</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">za %d let</string>
|
||||
<string name="abbreviated_in_days">za %d d</string>
|
||||
|
|
|
@ -214,7 +214,6 @@
|
|||
<string name="status_media_images">Delweddau</string>
|
||||
<string name="status_media_video">Fideo</string>
|
||||
<string name="state_follow_requested">Gofyn i ddilyn</string>
|
||||
<string name="no_content">dim cynnwys</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%dy </string>
|
||||
<string name="abbreviated_in_days"> %dd </string>
|
||||
|
|
|
@ -241,7 +241,6 @@
|
|||
<string name="status_media_images">Bilder</string>
|
||||
<string name="status_media_video">Video</string>
|
||||
<string name="state_follow_requested">Folgeanfrage gesendet</string>
|
||||
<string name="no_content">leer</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="follows_you">Folgt dir</string>
|
||||
<string name="pref_title_alway_show_sensitive_media">Heikle Inhalte immer anzeigen</string>
|
||||
|
|
|
@ -241,7 +241,6 @@
|
|||
<string name="status_media_images">Bildoj</string>
|
||||
<string name="status_media_video">Video</string>
|
||||
<string name="state_follow_requested">Sekvado petita</string>
|
||||
<string name="no_content">neniu enhavo</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">en %dj</string>
|
||||
<string name="abbreviated_in_days">en %dt</string>
|
||||
|
|
|
@ -228,7 +228,6 @@
|
|||
<string name="status_media_images">Imágenes</string>
|
||||
<string name="status_media_video">Video</string>
|
||||
<string name="state_follow_requested">Solicitud enviada</string>
|
||||
<string name="no_content">No hay nada aquí</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">en %dy</string>
|
||||
<string name="abbreviated_in_days">en %dd</string>
|
||||
|
|
|
@ -213,7 +213,6 @@
|
|||
<string name="status_media_images">Irudiak</string>
|
||||
<string name="status_media_video">Bideoak</string>
|
||||
<string name="state_follow_requested">Eskaera bidalita</string>
|
||||
<string name="no_content">Hutsik dago hau</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%du-an</string>
|
||||
<string name="abbreviated_in_days">%de-an</string>
|
||||
|
|
|
@ -213,7 +213,6 @@
|
|||
<string name="status_media_images">تصویرها</string>
|
||||
<string name="status_media_video">فیلم</string>
|
||||
<string name="state_follow_requested">تقاضای پیگیری شد</string>
|
||||
<string name="no_content">بدون هیچ محتوا</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">در %dسال</string>
|
||||
<string name="abbreviated_in_days">در %dر</string>
|
||||
|
|
|
@ -245,7 +245,6 @@
|
|||
<string name="status_media_images">Images</string>
|
||||
<string name="status_media_video">Vidéo</string>
|
||||
<string name="state_follow_requested">Demande de suivi effectuée</string>
|
||||
<string name="no_content">aucun contenu</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">en %da</string>
|
||||
<string name="abbreviated_in_days">en %dj</string>
|
||||
|
|
|
@ -226,7 +226,6 @@
|
|||
<string name="status_media_images">Képek</string>
|
||||
<string name="status_media_video">Videók</string>
|
||||
<string name="state_follow_requested">Követés kérelmezve</string>
|
||||
<string name="no_content">nincs tartalom</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="follows_you">Követ téged</string>
|
||||
<string name="pref_title_alway_show_sensitive_media">Mindig mutassa a szenzitív tartalmat</string>
|
||||
|
|
|
@ -239,7 +239,6 @@
|
|||
<string name="status_media_images">Immagini</string>
|
||||
<string name="status_media_video">Video</string>
|
||||
<string name="state_follow_requested">In attesa di approvazione</string>
|
||||
<string name="no_content">nessun contenuto</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">in %da</string>
|
||||
<string name="abbreviated_in_days">in %dg</string>
|
||||
|
|
|
@ -233,7 +233,6 @@
|
|||
<string name="status_media_images">画像</string>
|
||||
<string name="status_media_video">動画</string>
|
||||
<string name="state_follow_requested">フォローリクエスト中</string>
|
||||
<string name="no_content">下書きはありません</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%d年後</string>
|
||||
<string name="abbreviated_in_days">%d日後</string>
|
||||
|
|
|
@ -293,8 +293,6 @@
|
|||
|
||||
<string name="state_follow_requested">팔로우 요청함</string>
|
||||
|
||||
<string name="no_content">임시 저장된 게시물이 없습니다</string>
|
||||
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%d년 후</string>
|
||||
<string name="abbreviated_in_days">%d일 후</string>
|
||||
|
|
|
@ -236,7 +236,6 @@
|
|||
<string name="status_media_images">Afbeeldingen</string>
|
||||
<string name="status_media_video">Video</string>
|
||||
<string name="state_follow_requested">Volgverzoek verzonden</string>
|
||||
<string name="no_content">geen inhoud</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">over %dj</string>
|
||||
<string name="abbreviated_in_days">over %dd</string>
|
||||
|
|
|
@ -247,8 +247,6 @@
|
|||
|
||||
<string name="state_follow_requested">Forespørsel sendt</string>
|
||||
|
||||
<string name="no_content">ikke noe innhold</string>
|
||||
|
||||
<string name="abbreviated_in_days">om %dd</string>
|
||||
<string name="abbreviated_in_hours">om %dh</string>
|
||||
<string name="abbreviated_in_minutes">om %dm</string>
|
||||
|
@ -520,4 +518,5 @@
|
|||
|
||||
<string name="no_scheduled_status">Du har ingen planlagte statuser.</string>
|
||||
|
||||
</resources>
|
||||
<string name="no_saved_status">Du har ikke lagret noen kladder.</string>
|
||||
</resources>
|
||||
|
|
|
@ -209,7 +209,6 @@
|
|||
<string name="status_media_images">Imatges</string>
|
||||
<string name="status_media_video">Vidèo</string>
|
||||
<string name="state_follow_requested">Demanda d’abonament</string>
|
||||
<string name="no_content">I a pas cap de contengut</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">en %d ans</string>
|
||||
<string name="abbreviated_in_days">en %dd</string>
|
||||
|
|
|
@ -206,7 +206,6 @@
|
|||
<string name="status_media_images">Obrazy</string>
|
||||
<string name="status_media_video">Wideo</string>
|
||||
<string name="state_follow_requested">Wysłano prośbę o możliwość śledzenia</string>
|
||||
<string name="no_content">brak zawartości</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">w %d lata</string>
|
||||
<string name="abbreviated_in_days">w %d dni</string>
|
||||
|
|
|
@ -226,7 +226,6 @@
|
|||
<string name="status_media_images">Imagens</string>
|
||||
<string name="status_media_video">Vídeo</string>
|
||||
<string name="state_follow_requested">Solicitação enviada</string>
|
||||
<string name="no_content">sem conteúdo</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">em %dy</string>
|
||||
<string name="abbreviated_in_days">em %dd</string>
|
||||
|
@ -463,7 +462,7 @@
|
|||
<string name="poll_duration_3_days">3 dias</string>
|
||||
<string name="poll_duration_7_days">7 dias</string>
|
||||
<string name="add_poll_choice">Adicionar opção</string>
|
||||
<string name="poll_allow_multiple_choices">Múltiplas opções</string>
|
||||
<string name="poll_allow_multiple_choices">Múltiplos votos</string>
|
||||
<string name="poll_new_choice_hint">Opção %d</string>
|
||||
<string name="edit_poll">Editar</string>
|
||||
|
||||
|
@ -481,4 +480,8 @@
|
|||
<string name="description_status_bookmarked">Salvo</string>
|
||||
<string name="select_list_title">Selecionar lista</string>
|
||||
<string name="list">Lista</string>
|
||||
</resources>
|
||||
<string name="gradient_for_media">Mostrar blur em mídias ocultas</string>
|
||||
|
||||
<string name="no_scheduled_status">Sem toots agendados.</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -275,8 +275,6 @@
|
|||
|
||||
<string name="state_follow_requested">Запрошенные подписки</string>
|
||||
|
||||
<string name="no_content">ничего нет</string>
|
||||
|
||||
<!--Отметки времени у постов: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">через %dг</string>
|
||||
<string name="abbreviated_in_days">через %dд</string>
|
||||
|
|
|
@ -253,8 +253,6 @@
|
|||
|
||||
<string name="state_follow_requested">Prošnja za sledenje</string>
|
||||
|
||||
<string name="no_content">brez vsebine</string>
|
||||
|
||||
<string name="abbreviated_in_years">v %dy</string>
|
||||
<string name="abbreviated_in_days">v %dd</string>
|
||||
<string name="abbreviated_in_hours">v %dh</string>
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
<string name="error_video_upload_size">Videofiler måste vara mindre än 40MB.</string>
|
||||
<string name="error_media_upload_type">Den typen av fil kan inte laddas upp.</string>
|
||||
<string name="error_media_upload_opening">Den filen kunde inte öppnas.</string>
|
||||
<string name="error_media_upload_permission">Tillstånd att läsa media krävs.</string>
|
||||
<string name="error_media_download_permission">Tillstånd att lagra media krävs.</string>
|
||||
<string name="error_media_upload_permission">Behörighet att läsa media krävs.</string>
|
||||
<string name="error_media_download_permission">Behörighet att spara media krävs.</string>
|
||||
<string name="error_media_upload_image_or_video">Bilder och videoklipp kan inte båda bifogas i samma status.</string>
|
||||
<string name="error_media_upload_sending">Uppladdningen misslyckades.</string>
|
||||
<string name="error_sender_account_gone">Misslyckades med att få ett inloggningsnamn.</string>
|
||||
<string name="error_sender_account_gone">Kunde inte skicka toot.</string>
|
||||
<string name="title_home">Hem</string>
|
||||
<string name="title_notifications">Notifikationer</string>
|
||||
<string name="title_public_local">Lokalt</string>
|
||||
|
@ -109,7 +109,7 @@
|
|||
<string name="action_links">Länkar</string>
|
||||
<string name="action_mentions">Omnämnanden</string>
|
||||
<string name="action_hashtags">Hashtaggar</string>
|
||||
<string name="action_open_reblogger">Öppna knuffa författare</string>
|
||||
<string name="action_open_reblogger">Öppna knuff författare</string>
|
||||
<string name="action_open_reblogged_by">Visa knuffar</string>
|
||||
<string name="action_open_faved_by">Visa favoriter</string>
|
||||
<string name="title_hashtags_dialog">Hashtaggar</string>
|
||||
|
@ -117,7 +117,7 @@
|
|||
<string name="title_links_dialog">Länkar</string>
|
||||
<string name="action_open_media_n">Öppna media #%d</string>
|
||||
<string name="download_image">Laddar ned %1$s</string>
|
||||
<string name="action_copy_link">Kopiera länken</string>
|
||||
<string name="action_copy_link">Kopiera länk</string>
|
||||
<string name="action_open_as">Öppen som %s</string>
|
||||
<string name="action_share_as">Dela som …</string>
|
||||
<string name="send_status_link_to">Dela toot-URL till…</string>
|
||||
|
@ -158,8 +158,8 @@
|
|||
<string name="visibility_unlisted">Olistad: Visa inte i offentliga tidslinjer</string>
|
||||
<string name="visibility_private">Enbart-följare: Ses enbart av följare</string>
|
||||
<string name="visibility_direct">Direkt: Skicka endast till nämnda användare</string>
|
||||
<string name="pref_title_edit_notification_settings">Redigera notifieringar</string>
|
||||
<string name="pref_title_notifications_enabled">Notifieringar</string>
|
||||
<string name="pref_title_edit_notification_settings">Notifikationer</string>
|
||||
<string name="pref_title_notifications_enabled">Notifikationer</string>
|
||||
<string name="pref_title_notification_alerts">Alarm</string>
|
||||
<string name="pref_title_notification_alert_sound">Meddela med ljud</string>
|
||||
<string name="pref_title_notification_alert_vibrate">Meddela med vibration</string>
|
||||
|
@ -173,14 +173,14 @@
|
|||
<string name="pref_title_app_theme">Applikationstema</string>
|
||||
<string name="pref_title_timelines">Tidslinjer</string>
|
||||
<string name="pref_title_timeline_filters">Filter</string>
|
||||
<string name="app_them_dark">Mörk</string>
|
||||
<string name="app_theme_light">Ljus</string>
|
||||
<string name="app_them_dark">Mörkt</string>
|
||||
<string name="app_theme_light">Ljust</string>
|
||||
<string name="app_theme_black">Svart</string>
|
||||
<string name="app_theme_auto">Automatiskt vid solnedgång</string>
|
||||
<string name="app_theme_system">Använd systemdesign</string>
|
||||
<string name="pref_title_browser_settings">Webbläsare</string>
|
||||
<string name="pref_title_custom_tabs">Använd Chrome-anpassade flikar</string>
|
||||
<string name="pref_title_hide_follow_button">Dölj skriv-knappen medan du scrollar</string>
|
||||
<string name="pref_title_hide_follow_button">Dölj skriv-knappen vid skrollning</string>
|
||||
<string name="pref_title_language">Språk</string>
|
||||
<string name="pref_title_status_filter">Filtrering av tidslinje</string>
|
||||
<string name="pref_title_status_tabs">Flikar</string>
|
||||
|
@ -208,11 +208,11 @@
|
|||
<string name="notification_mention_name">Nya omnämnanden</string>
|
||||
<string name="notification_mention_descriptions">Notifieringar om nya omnämnanden</string>
|
||||
<string name="notification_follow_name">Nya följare</string>
|
||||
<string name="notification_follow_description">Notifieringar angående nya följare</string>
|
||||
<string name="notification_follow_description">Notifieringar om nya följare</string>
|
||||
<string name="notification_boost_name">Knuffar</string>
|
||||
<string name="notification_boost_description">Notifieringar när dina toot blir knuffade</string>
|
||||
<string name="notification_boost_description">Notifieringar när dina toots blir knuffade</string>
|
||||
<string name="notification_favourite_name">Favoriter</string>
|
||||
<string name="notification_favourite_description">Notifieringar när dina toot blir markerade som favoriter</string>
|
||||
<string name="notification_favourite_description">Notifieringar när dina toots blir markerade som favoriter</string>
|
||||
<string name="notification_mention_format">%s omnämnde dig</string>
|
||||
<string name="notification_summary_large">%1$s, %2$s, %3$s och %4$d andra</string>
|
||||
<string name="notification_summary_medium">%1$s, %2$s, och %3$s</string>
|
||||
|
@ -239,8 +239,7 @@
|
|||
<string name="status_share_link">Dela länk till toot</string>
|
||||
<string name="status_media_images">Bilder</string>
|
||||
<string name="status_media_video">Video</string>
|
||||
<string name="state_follow_requested">Följarförfrågning</string>
|
||||
<string name="no_content">inget innehåll</string>
|
||||
<string name="state_follow_requested">Följarförfrågad</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">om %dy</string>
|
||||
<string name="abbreviated_in_days">om %dd</string>
|
||||
|
@ -273,11 +272,11 @@
|
|||
<string name="error_rename_list">Kunde inte byta namn på lista</string>
|
||||
<string name="error_delete_list">Kunde inte radera lista</string>
|
||||
<string name="action_create_list">Skapa en lista</string>
|
||||
<string name="action_rename_list">Byt namn på lista</string>
|
||||
<string name="action_delete_list">Ta bort denna lista</string>
|
||||
<string name="action_edit_list">Redigera listan</string>
|
||||
<string name="action_rename_list">Byt namn</string>
|
||||
<string name="action_delete_list">Ta bort</string>
|
||||
<string name="action_edit_list">Ändra</string>
|
||||
<string name="hint_search_people_list">Sök efter personer du följer</string>
|
||||
<string name="action_add_to_list">Lägga till kontot i listan</string>
|
||||
<string name="action_add_to_list">Lägg till konto i listan</string>
|
||||
<string name="action_remove_from_list">Ta bort kontot från listan</string>
|
||||
<string name="compose_active_account_description">Inlägg med kontot %1$s</string>
|
||||
<string name="error_failed_set_caption">Misslyckades med att ange bildtext</string>
|
||||
|
@ -302,7 +301,7 @@
|
|||
<string name="expand_collapse_all_statuses">Expandera/Dölj alla status</string>
|
||||
<string name="action_open_toot">Öppna toot</string>
|
||||
<string name="restart_required">Omstart av appen krävs</string>
|
||||
<string name="restart_emoji">Du måste starta om Tusky för att kunna tillämpa ändringarna</string>
|
||||
<string name="restart_emoji">Du måste starta om Tusky för att tillämpa ändringarna</string>
|
||||
<string name="later">Senare</string>
|
||||
<string name="restart">Starta om</string>
|
||||
<string name="caption_systememoji">Standard-emojis för din enhet</string>
|
||||
|
@ -330,9 +329,9 @@
|
|||
<item quantity="other"><b>%1$s</b> Favoriter</item>
|
||||
</plurals>
|
||||
<plurals name="reblogs">
|
||||
<item quantity="one"><b>%s</b> Knuffa</item>
|
||||
<item quantity="other"><b>%s</b> Knuffar</item>
|
||||
</plurals>
|
||||
<item quantity="one"><b>%s</b> Knuff</item>
|
||||
<item quantity="other"><b>%s</b> Knuffar</item>
|
||||
</plurals>
|
||||
<string name="title_reblogged_by">Knuffad av</string>
|
||||
<string name="title_favourited_by">Favoriserad av</string>
|
||||
<string name="conversation_1_recipients">%1$s</string>
|
||||
|
@ -377,7 +376,7 @@
|
|||
<string name="notification_clear_text">Är du säker på att du vill rensa dina notifieringar permanent\?</string>
|
||||
|
||||
<string name="action_delete_and_redraft">Radera och skriv nytt</string>
|
||||
<string name="dialog_redraft_toot_warning">Radera och skriva ny toot\?</string>
|
||||
<string name="dialog_redraft_toot_warning">Radera och skriv ny toot\?</string>
|
||||
|
||||
<string name="poll_info_format"> <!-- 15 röster • 1 timme kvar --> %1$s • %2$s</string>
|
||||
<plurals name="poll_info_votes">
|
||||
|
@ -391,7 +390,7 @@
|
|||
<string name="poll_vote">Rösta</string>
|
||||
|
||||
|
||||
<string name="pref_title_notification_filter_poll">omröstningen är avslutad</string>
|
||||
<string name="pref_title_notification_filter_poll">omröstning är avslutad</string>
|
||||
<string name="notification_poll_name">Omröstningar</string>
|
||||
<string name="notification_poll_description">Notifieringar när omröstningar har avslutats</string>
|
||||
|
||||
|
@ -428,7 +427,7 @@
|
|||
<string name="confirmation_domain_unmuted">%s inte tystnad längre</string>
|
||||
|
||||
<string name="mute_domain_warning">Är du säker på att du vill blockera allt från %s\? Du kommer inte kunna se något innehåll från denna domän i publika tidslinje eller i dina notifieringar. Dina följare på domänen kommer inte att bli borttagna.</string>
|
||||
<string name="mute_domain_warning_dialog_ok">Dölj hela domän</string>
|
||||
<string name="mute_domain_warning_dialog_ok">Dölj hela domänen</string>
|
||||
|
||||
<string name="caption_notoemoji">Google\'s nuvarande emojis</string>
|
||||
<string name="button_continue">Fortsätt</string>
|
||||
|
@ -440,7 +439,7 @@
|
|||
<string name="failed_report">Misslyckades att anmäla</string>
|
||||
<string name="failed_fetch_statuses">Misslyckades att hämta status</string>
|
||||
<string name="report_description_1">Anmälan kommer att skickas till din serveradminstratör. Du kan beskriva varför du anmäler kontot nedan:</string>
|
||||
<string name="report_description_remote_instance">Kontot är från en annan server. Skicka en avidentifierad kopia av anmälan dit också\?</string>
|
||||
<string name="report_description_remote_instance">Kontot är från en annan server. Skicka en anonym kopia av anmälan dit också\?</string>
|
||||
|
||||
<string name="pref_title_show_notifications_filter">Visa notifikationsfilter</string>
|
||||
<string name="filter_dialog_whole_word">Helt ord</string>
|
||||
|
@ -477,4 +476,8 @@
|
|||
<string name="description_status_bookmarked">Bokmärkt</string>
|
||||
<string name="select_list_title">Välj lista</string>
|
||||
<string name="list">Lista</string>
|
||||
</resources>
|
||||
<string name="gradient_for_media">Visa färgglada gradienter för gömd media</string>
|
||||
|
||||
<string name="no_scheduled_status">Du har inga schemalagda statusar.</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -194,7 +194,6 @@
|
|||
<string name="status_media_images">படங்கள்</string>
|
||||
<string name="status_media_video">காணொளி</string>
|
||||
<string name="state_follow_requested">கோரிக்கையைப் பின்பற்றவும்</string>
|
||||
<string name="no_content">எந்த உள்ளடக்கமும் இல்லை</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%dஆ-முன்</string>
|
||||
<string name="abbreviated_in_days">%dநா-முன்</string>
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
<string name="error_network">Bir ağ hatası oluştu! Lütfen bağlantınızı kontrol edin ve tekrar deneyin!</string>
|
||||
<string name="error_empty">Bu alan boş bırakılamaz.</string>
|
||||
<string name="error_invalid_domain">Girilen alan adı geçersiz</string>
|
||||
<string name="error_failed_app_registration">Bu sunucuda kimlik doğrulama başarısız oldu.</string>
|
||||
<string name="error_no_web_browser_found">Kullanılabilir tarayıcı bulunmadı.</string>
|
||||
<string name="error_failed_app_registration">Kimlik doğrulama başarısız oldu.</string>
|
||||
<string name="error_no_web_browser_found">Kullanılabilir bir web tarayıcı bulunmadı.</string>
|
||||
<string name="error_authorization_unknown">Tanımlanamayan bir yetkilendirme hatası oluştu.</string>
|
||||
<string name="error_authorization_denied">Kimlik doğrulama reddedildi.</string>
|
||||
<string name="error_retrieving_oauth_token">Giriş jetonu alınamadı.</string>
|
||||
<string name="error_retrieving_oauth_token">Giriş tokenı alınamadı.</string>
|
||||
<string name="error_compose_character_limit">İleti çok uzun!</string>
|
||||
<string name="error_image_upload_size">Dosya 8MB\'ten küçük olmalı.</string>
|
||||
<string name="error_video_upload_size">Video dosyaları 40 MB’den az olmalıdır.</string>
|
||||
<string name="error_image_upload_size">Dosya 8MB\'den küçük olmalı.</string>
|
||||
<string name="error_video_upload_size">Video dosyaları 40MB’den küçük olmalıdır.</string>
|
||||
<string name="error_media_upload_type">Bu tür bir dosya yüklenemiyor.</string>
|
||||
<string name="error_media_upload_opening">Dosya açılamadı.</string>
|
||||
<string name="error_media_upload_permission">Medya okuma izni gerekiyor.</string>
|
||||
<string name="error_media_upload_permission">Medya erişim izni gerekiyor.</string>
|
||||
<string name="error_media_download_permission">Medya yazma izni gerekiyor.</string>
|
||||
<string name="error_media_upload_image_or_video">Aynı iletiye hem video hem resim eklenemez.</string>
|
||||
<string name="error_media_upload_sending">Yükleme başarsız.</string>
|
||||
|
@ -34,7 +34,7 @@
|
|||
<string name="title_favourites">Favoriler</string>
|
||||
<string name="title_mutes">Sesize alınmış kullanıcılar</string>
|
||||
<string name="title_blocks">Engellenmiş kullanıcılar</string>
|
||||
<string name="title_follow_requests">Takip Etme İstekleri</string>
|
||||
<string name="title_follow_requests">Takip İstekleri</string>
|
||||
<string name="title_edit_profile">Profil düzenle</string>
|
||||
<string name="title_saved_toot">Taslaklar</string>
|
||||
<string name="title_licenses">Lisanslar</string>
|
||||
|
@ -42,27 +42,27 @@
|
|||
<string name="status_boosted_format">%s yineledi</string>
|
||||
<string name="status_sensitive_media_title">Hasas içerik</string>
|
||||
<string name="status_media_hidden_title">Gizlenmiş medya</string>
|
||||
<string name="status_sensitive_media_directions">Görüntülemek için tıklayın</string>
|
||||
<string name="status_sensitive_media_directions">Görüntülemek için dokunun</string>
|
||||
<string name="status_content_warning_show_more">Daha Fazla</string>
|
||||
<string name="status_content_warning_show_less">Daha Az</string>
|
||||
<string name="status_content_warning_show_less">Daha az</string>
|
||||
<string name="status_content_show_more">Genişlet</string>
|
||||
<string name="status_content_show_less">Daralt</string>
|
||||
<string name="message_empty">Burada hiçbir şey yok.</string>
|
||||
<string name="footer_empty">Burada henüz hiçbir şey yok. Yenilemek için aşağıya çekin!</string>
|
||||
<string name="notification_reblog_format">%s iletini yineledi</string>
|
||||
<string name="notification_favourite_format">%s ileti favorilerine ekledi</string>
|
||||
<string name="notification_favourite_format">%s iletini favorilerine ekledi</string>
|
||||
<string name="notification_follow_format">%s seni takip etti</string>
|
||||
<string name="report_username_format">\@%s bildir</string>
|
||||
<string name="report_comment_hint">Daha fazla yorum?</string>
|
||||
<string name="action_quick_reply">Hızlı Cevapla</string>
|
||||
<string name="action_reply">Yanıtla</string>
|
||||
<string name="action_reblog">Yinele</string>
|
||||
<string name="action_favourite">Favori</string>
|
||||
<string name="action_favourite">Favorile</string>
|
||||
<string name="action_more">Daha fazla</string>
|
||||
<string name="action_compose">Oluştur</string>
|
||||
<string name="action_login">Mastodon ile giriş yap</string>
|
||||
<string name="action_logout">Çıkış Yap</string>
|
||||
<string name="action_logout_confirm">%1$s hesabından çıkmak istediğinize emin misiniz\?</string>
|
||||
<string name="action_logout_confirm">%1$s hesabından çıkmak istediğine emin misin\?</string>
|
||||
<string name="action_follow">Takip et</string>
|
||||
<string name="action_unfollow">Takibi bırak</string>
|
||||
<string name="action_block">Engelle</string>
|
||||
|
@ -107,7 +107,7 @@
|
|||
<string name="download_image">%1$s indiriliyor</string>
|
||||
<string name="action_copy_link">Bağlantıyı kopyala</string>
|
||||
<string name="action_open_as">Farklı aç %s</string>
|
||||
<string name="action_share_as">... olarak paylaş</string>
|
||||
<string name="action_share_as">Farklı paylaş…</string>
|
||||
<string name="send_status_link_to">İletinin adresini paylaş…</string>
|
||||
<string name="send_status_content_to">İletiyi paylaş…</string>
|
||||
<string name="send_media_to">Medyayı paylaş…</string>
|
||||
|
@ -119,7 +119,7 @@
|
|||
<string name="hint_domain">Hangi sunucu?</string>
|
||||
<string name="hint_compose">Neler oluyor?</string>
|
||||
<string name="hint_content_warning">İçerik uyarısı</string>
|
||||
<string name="hint_display_name">Görünen ad</string>
|
||||
<string name="hint_display_name">Görüntülenecek isim</string>
|
||||
<string name="hint_note">Biyo</string>
|
||||
<string name="hint_search">Ara…</string>
|
||||
<string name="search_no_results">Sonuç bulunamadı</string>
|
||||
|
@ -128,33 +128,33 @@
|
|||
<string name="label_header">Başlık</string>
|
||||
<string name="link_whats_an_instance">Sunucu nedir?</string>
|
||||
<string name="login_connection">Bağlantı kuruluyor…</string>
|
||||
<string name="dialog_whats_an_instance">Burada her hangi bir Mastodon sunucusunun adresi (mastodon.social, icosahedron.website, social.tchncs.de, ve <a href="https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md">daha fazla!</a>) girilebiliri.
|
||||
\n
|
||||
\nEğer hesabınız henüz yok ise katılmak istediğiniz sunucunun adresini girerek hesap oluşturabilirsiniz
|
||||
\n
|
||||
\nHer bir sunucu kendi hesap kayıtlarını tutar ancak diğer sunucularda bulunan insanlarla aynı sitedeymişçesine iletişime geçip takip edebilirsiniz.
|
||||
\n
|
||||
<string name="dialog_whats_an_instance">Burada her hangi bir Mastodon sunucusunun adresi (mastodon.social, icosahedron.website, social.tchncs.de, ve <a href="https://github.com/tootsuite/mastodon/blob/master/docs/Using-Mastodon/List-of-Mastodon-instances.md">daha fazlasını</a>) girebilirsin!
|
||||
\n
|
||||
\nHenüz hesabın yok ise katılmak istediğin sunucunun adresini girerek hesap oluşturabilirsin
|
||||
\n
|
||||
\nHer bir sunucu kendi hesap kayıtlarını tutar ancak diğer sunucularda bulunan insanlarla aynı sitedeymişçesine iletişime geçip takip edebilirsin.
|
||||
\n
|
||||
\nDaha fazla bilgi için <a href="https://mastodon.social/about">mastodon.social</a>. </string>
|
||||
<string name="dialog_title_finishing_media_upload">Medya Yükleme Bitiriliyor</string>
|
||||
<string name="dialog_title_finishing_media_upload">Medya Yükleme Tamamlanıyor</string>
|
||||
<string name="dialog_message_uploading_media">Yükleniyor…</string>
|
||||
<string name="dialog_download_image">İndir</string>
|
||||
<string name="dialog_message_cancel_follow_request">Takip isteğini iptal et?</string>
|
||||
<string name="dialog_unfollow_warning">Takibi bırak?</string>
|
||||
<string name="dialog_delete_toot_warning">Bu iletiyi silmek istiyor musunuz\?</string>
|
||||
<string name="visibility_public">Genel: Genel zaman çizelgelerine gönder</string>
|
||||
<string name="visibility_unlisted">Listelenmemiş: Genel zaman çizelgelerinde gösterme</string>
|
||||
<string name="visibility_private">Özel: Sadece takipçiler gönder</string>
|
||||
<string name="visibility_direct">Doğrudan: Sadece bahsedilen kullanıcılara gönder</string>
|
||||
<string name="dialog_message_cancel_follow_request">Takip isteği iptal edilsin mi\?</string>
|
||||
<string name="dialog_unfollow_warning">Takibi bırakmak istiyor musun\?</string>
|
||||
<string name="dialog_delete_toot_warning">Bu iletiyi silmek istiyor musun\?</string>
|
||||
<string name="visibility_public">Genel: Herkese açık zaman çizelgesinde göster</string>
|
||||
<string name="visibility_unlisted">Liste dışı: Herkese açık zaman çizelgelerinde gösterme</string>
|
||||
<string name="visibility_private">Takipçiler: Sadece takipçilere göster</string>
|
||||
<string name="visibility_direct">Doğrudan: Sadece bahsedilen kullanıcılara göster</string>
|
||||
<string name="pref_title_edit_notification_settings">Bildirimler</string>
|
||||
<string name="pref_title_notifications_enabled">Bildirimler</string>
|
||||
<string name="pref_title_notification_alerts">Uyarılar</string>
|
||||
<string name="pref_title_notification_alert_sound">Sesli uyarı</string>
|
||||
<string name="pref_title_notification_alert_vibrate">Titreşim ile uyarı</string>
|
||||
<string name="pref_title_notification_alert_sound">Sesle bildir</string>
|
||||
<string name="pref_title_notification_alert_vibrate">Titreşimle bildir</string>
|
||||
<string name="pref_title_notification_alert_light">Bildirim ışığıyla bildir</string>
|
||||
<string name="pref_title_notification_filters">Beni bildir</string>
|
||||
<string name="pref_title_notification_filter_mentions">Bahsedilince</string>
|
||||
<string name="pref_title_notification_filter_follows">Takip edilince</string>
|
||||
<string name="pref_title_notification_filter_reblogs">İletilerim yinelenince</string>
|
||||
<string name="pref_title_notification_filters">Bildirim ayarları</string>
|
||||
<string name="pref_title_notification_filter_mentions">bahsedilince</string>
|
||||
<string name="pref_title_notification_filter_follows">takip edilince</string>
|
||||
<string name="pref_title_notification_filter_reblogs">iletilerim yinelenince</string>
|
||||
<string name="pref_title_notification_filter_favourites">iletilerim favorilenince</string>
|
||||
<string name="pref_title_appearance_settings">Görünüm</string>
|
||||
<string name="pref_title_app_theme">Uygulama Teması</string>
|
||||
|
@ -164,7 +164,7 @@
|
|||
<string name="app_theme_black">Siyah</string>
|
||||
<string name="app_theme_auto">Gün batımında otomatik</string>
|
||||
<string name="pref_title_browser_settings">Tarayıcı</string>
|
||||
<string name="pref_title_custom_tabs">Chrome Özel Sekmelerini Kullan</string>
|
||||
<string name="pref_title_custom_tabs">Tarayıcı Özel Sekmelerini Kullan</string>
|
||||
<string name="pref_title_hide_follow_button">Kaydırırken yeni ileti düğmesi gizlensin</string>
|
||||
<string name="pref_title_status_filter">Zaman çizelgesi filtreleme</string>
|
||||
<string name="pref_title_status_tabs">Sekmeler</string>
|
||||
|
@ -177,26 +177,26 @@
|
|||
<string name="pref_title_http_proxy_server">HTTP ağ vekili sunucusu</string>
|
||||
<string name="pref_title_http_proxy_port">HTTP ağ vekili bağlantı noktası</string>
|
||||
<string name="pref_default_post_privacy">Varsayılan ileti gizliliği</string>
|
||||
<string name="pref_default_media_sensitivity">Her zaman hassas olarak işaretle</string>
|
||||
<string name="pref_default_media_sensitivity">Medyaları her zaman hassas olarak işaretle</string>
|
||||
<string name="pref_publishing">Yayınlama (sunucuyla eşitlenir)</string>
|
||||
<string name="pref_failed_to_sync">Ayarlar senkronize edilemedi</string>
|
||||
<string name="post_privacy_public">Herkese açık</string>
|
||||
<string name="post_privacy_unlisted">Liste dışı</string>
|
||||
<string name="post_privacy_followers_only">Sadece takip edenler</string>
|
||||
<string name="post_privacy_followers_only">Sadece takipçiler</string>
|
||||
<string name="pref_status_text_size">İleti metin boyutu</string>
|
||||
<string name="status_text_size_smallest">En küçük</string>
|
||||
<string name="status_text_size_smallest">Çok küçük</string>
|
||||
<string name="status_text_size_small">Küçük</string>
|
||||
<string name="status_text_size_medium">Orta</string>
|
||||
<string name="status_text_size_large">Büyük</string>
|
||||
<string name="status_text_size_largest">En büyük</string>
|
||||
<string name="notification_mention_name">Yeni Bahsedilenler</string>
|
||||
<string name="notification_mention_descriptions">Yeni bahsedilenler hakkında bildirim</string>
|
||||
<string name="notification_follow_name">Yeni Takipçiler</string>
|
||||
<string name="notification_follow_description">Yeni takipçiler hakkında bildirim</string>
|
||||
<string name="status_text_size_largest">Çok büyük</string>
|
||||
<string name="notification_mention_name">Senden bahsedildi</string>
|
||||
<string name="notification_mention_descriptions">Senden bahsedenler hakkında bildirim</string>
|
||||
<string name="notification_follow_name">Yeni Takipçi</string>
|
||||
<string name="notification_follow_description">Yeni takipçi hakkında bildirim</string>
|
||||
<string name="notification_boost_name">Yinelemeler</string>
|
||||
<string name="notification_boost_description">İletilerin yinelendiğinde</string>
|
||||
<string name="notification_favourite_name">Favoriler</string>
|
||||
<string name="notification_favourite_description">İletilerin favori olarak işaretlendiğinde</string>
|
||||
<string name="notification_favourite_description">İletilerim favori olarak işaretlendiğinde</string>
|
||||
<string name="notification_mention_format">%s senden bahsetti</string>
|
||||
<string name="notification_summary_large">%1$s, %2$s, %3$s ve %4$d diğerleri</string>
|
||||
<string name="notification_summary_medium">%1$s, %2$s ve %3$s</string>
|
||||
|
@ -212,9 +212,8 @@
|
|||
to show we do not mean the software is gratis. Source: https://www.gnu.org/philosophy/free-sw.html
|
||||
* the url can be changed to link to the localized version of the license.
|
||||
-->
|
||||
<string name="about_project_site"> Proje Web sitesi:\n
|
||||
https://tusky.app
|
||||
</string>
|
||||
<string name="about_project_site">Projenin internet sitesi:
|
||||
\n https://tusky.app</string>
|
||||
<string name="about_bug_feature_request_site">Hata raporları & özellik istekleri:
|
||||
\n https://github.com/tuskyapp/Tusky/issues</string>
|
||||
<string name="about_tusky_account">Tusky\'in Profili</string>
|
||||
|
@ -223,19 +222,18 @@
|
|||
<string name="status_media_images">Görseller</string>
|
||||
<string name="status_media_video">Video</string>
|
||||
<string name="state_follow_requested">Takip istekleri</string>
|
||||
<string name="no_content">içerik yok</string>
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%dy</string>
|
||||
<string name="abbreviated_in_days">%dd</string>
|
||||
<string name="abbreviated_in_hours">%dh</string>
|
||||
<string name="abbreviated_in_minutes">%dm</string>
|
||||
<string name="abbreviated_in_seconds">%ds</string>
|
||||
<string name="abbreviated_years_ago">%dy yıl önce</string>
|
||||
<string name="abbreviated_days_ago">%dd gün önce</string>
|
||||
<string name="abbreviated_hours_ago">%dh saat önce</string>
|
||||
<string name="abbreviated_minutes_ago">%dm dk önce</string>
|
||||
<string name="abbreviated_seconds_ago">%ds sn önce</string>
|
||||
<string name="follows_you">Sizi takip ediyor</string>
|
||||
<string name="abbreviated_years_ago">%dy</string>
|
||||
<string name="abbreviated_days_ago">%dd</string>
|
||||
<string name="abbreviated_hours_ago">%dh</string>
|
||||
<string name="abbreviated_minutes_ago">%dm</string>
|
||||
<string name="abbreviated_seconds_ago">%ds</string>
|
||||
<string name="follows_you">Seni takip ediyor</string>
|
||||
<string name="pref_title_alway_show_sensitive_media">Her zaman hassas içerikleri göster</string>
|
||||
<string name="title_media">Medya</string>
|
||||
|
||||
|
@ -246,11 +244,11 @@
|
|||
<string name="title_lists">Listeler</string>
|
||||
<string name="title_list_timeline">Zaman çizelgesini listele</string>
|
||||
<string name="compose_active_account_description">%1$s hesabıyla gönderiliyor</string>
|
||||
<string name="hint_describe_for_visually_impaired">Görme engelliler için açıklama
|
||||
\n(%d karakter limiti)</string>
|
||||
<string name="hint_describe_for_visually_impaired">Görme engelliler için açıklama
|
||||
\n(%d karakter sınırı)</string>
|
||||
<string name="action_set_caption">Başlık belirle</string>
|
||||
<string name="action_remove">Kaldır</string>
|
||||
<string name="lock_account_label">Hesabı Gizle</string>
|
||||
<string name="lock_account_label">Hesabı Kilitle</string>
|
||||
<string name="lock_account_label_description">Aktif edilirse takipçileri elle onaylamanız gerekir</string>
|
||||
<string name="compose_save_draft">Taslaklara kaydedilsin mi\?</string>
|
||||
<string name="send_toot_notification_title">İleti gönderiliyor…</string>
|
||||
|
@ -261,17 +259,17 @@
|
|||
<string name="action_compose_shortcut">Oluştur</string>
|
||||
<string name="error_no_custom_emojis">%s sunucunuzun özel emoji seti yok</string>
|
||||
<string name="copy_to_clipboard_success">Panoya kopyalandı</string>
|
||||
<string name="emoji_style">Emoji Stili</string>
|
||||
<string name="emoji_style">Emoji tipi</string>
|
||||
<string name="system_default">Sistem varsayılanı</string>
|
||||
<string name="download_fonts">Emoji setini kullanabilmek için indirmeniz gerekli</string>
|
||||
<string name="performing_lookup_title">Araştırılıyor…</string>
|
||||
<string name="expand_collapse_all_statuses">Tüm durumları Genişlet/Daralt</string>
|
||||
<string name="action_open_toot">İleti aç</string>
|
||||
<string name="restart_required">Uygulamayı yeniden başlatmanız gerekiyor</string>
|
||||
<string name="expand_collapse_all_statuses">Tüm iletileri genişlet/daralt</string>
|
||||
<string name="action_open_toot">İletiyi aç</string>
|
||||
<string name="restart_required">Uygulamayı yeniden başlatman gerekiyor</string>
|
||||
<string name="restart_emoji">Değişikliklerin uygulanabilmesi için uygulama yeniden başlatılmalı</string>
|
||||
<string name="later">Sonra</string>
|
||||
<string name="restart">Yeniden başlat</string>
|
||||
<string name="caption_systememoji">Cihazınızın varsayılan emoji seti</string>
|
||||
<string name="caption_systememoji">Cihaz varsayılan emoji seti</string>
|
||||
<string name="caption_blobmoji">Android 4.4 — 7.1\'den bilinen baloncuk emojisi</string>
|
||||
<string name="caption_twemoji">Mastodon\'un standart emoji seti</string>
|
||||
<string name="download_failed">İndirme başarısız</string>
|
||||
|
@ -281,7 +279,7 @@
|
|||
<string name="license_apache_2">Apache Lisansı altında lisanslanmıştır (kopya aşağıda)</string>
|
||||
<string name="license_cc_by_4">CC-BY 4.0</string>
|
||||
<string name="license_cc_by_sa_4">CC-BY-SA 4.0</string>
|
||||
<string name="profile_metadata_label">Profil Meta verisi</string>
|
||||
<string name="profile_metadata_label">Profil meta verisi</string>
|
||||
<string name="profile_metadata_add">veri ekle</string>
|
||||
<string name="profile_metadata_label_label">Etiket</string>
|
||||
<string name="profile_metadata_content_label">İçerik</string>
|
||||
|
@ -290,23 +288,23 @@
|
|||
<string name="unpin_action">Sabitlemeyi kaldır</string>
|
||||
<string name="pin_action">Sabitle</string>
|
||||
<plurals name="favs">
|
||||
<item quantity="one"><b>%1$s</b> Favori</item>
|
||||
<item quantity="other"><b>%1$s</b> Favoriler</item>
|
||||
</plurals>
|
||||
<item quantity="one"><b>%1$s</b> Favori</item>
|
||||
<item quantity="other"><b>%1$s</b> Favori</item>
|
||||
</plurals>
|
||||
<plurals name="reblogs">
|
||||
<item quantity="one"><b>%s</b> Yinelenen</item>
|
||||
<item quantity="other"><b>%s</b> Yinelenenler</item>
|
||||
<item quantity="one"><b>%s</b> Yineleme</item>
|
||||
<item quantity="other"><b>%s</b> Yineleme</item>
|
||||
</plurals>
|
||||
<string name="title_reblogged_by">tarafından yinelendi</string>
|
||||
<string name="title_favourited_by">Tarafından favorilendi</string>
|
||||
<string name="title_favourited_by">favoriledi</string>
|
||||
<string name="conversation_1_recipients">%1$s</string>
|
||||
<string name="conversation_2_recipients">%1$s ve %2$s</string>
|
||||
<string name="conversation_more_recipients">%1$s, %2$s ve %3$d daha fazlası</string>
|
||||
<string name="max_tab_number_reached">%1$d maksimum sekme sayısına ulaşıldı</string>
|
||||
<string name="title_domain_mutes">Gizli alanadları</string>
|
||||
<string name="title_domain_mutes">Gizlenmiş alan adları</string>
|
||||
<string name="action_unreblog">Yinelemeyi kaldır</string>
|
||||
<string name="action_unfavourite">Favoriyi kaldır</string>
|
||||
<string name="action_view_domain_mutes">Gizli alan adları</string>
|
||||
<string name="action_view_domain_mutes">Gizlenmiş alan adları</string>
|
||||
<string name="action_mute_domain">%s alan adını sessize al</string>
|
||||
<string name="action_links">Bağlantılar</string>
|
||||
<string name="action_hashtags">Hashtag\'ler</string>
|
||||
|
@ -318,7 +316,7 @@
|
|||
<string name="downloading_media">Medya indiriliyor</string>
|
||||
|
||||
<string name="mute_domain_warning">%s alan adınından gelen her şeyi engellemek istediğinizden emin misiniz\? Bu alan adından gelen içeriği herhangi bir genel zaman çizelgesinde veya bildirimlerinizde göremezsiniz. Bu alan adındaki takipçileriniz de kaldırılacak.</string>
|
||||
<string name="pref_title_notification_filter_poll">Anket sona erince</string>
|
||||
<string name="pref_title_notification_filter_poll">anket sona erince</string>
|
||||
<string name="pref_title_timeline_filters">Filtreler</string>
|
||||
|
||||
<string name="app_theme_system">Sistem tasarımını kullan</string>
|
||||
|
@ -336,7 +334,7 @@
|
|||
<string name="filter_edit_dialog_title">Filtreyi düzenle</string>
|
||||
<string name="filter_dialog_remove_button">Kaldır</string>
|
||||
<string name="filter_dialog_update_button">Güncelle</string>
|
||||
<string name="filter_dialog_whole_word">Tüm dünya</string>
|
||||
<string name="filter_dialog_whole_word">Tüm kelime</string>
|
||||
<string name="filter_dialog_whole_word_description">Anahtar kelime veya kelime öbeği yalnızca alfasayısal olduğunda, yalnızca tüm sözcükle eşleşirse uygulanır</string>
|
||||
<string name="filter_add_description">Filtrelenecek ifade</string>
|
||||
|
||||
|
@ -347,7 +345,7 @@
|
|||
<string name="action_rename_list">Listeyi yeniden adlandır</string>
|
||||
<string name="action_delete_list">Listeyi sil</string>
|
||||
<string name="action_edit_list">Listeyi düzenle</string>
|
||||
<string name="hint_search_people_list">Takip ettiğiniz kişileri ara</string>
|
||||
<string name="hint_search_people_list">Takip ettiğim kişilerde ara</string>
|
||||
<string name="action_add_to_list">Listeye hesap ekle</string>
|
||||
<string name="action_remove_from_list">Hesabı listeden kaldır</string>
|
||||
|
||||
|
@ -376,7 +374,7 @@
|
|||
<string name="compose_shortcut_long_label">İleti Oluştur</string>
|
||||
<string name="compose_shortcut_short_label">Oluştur</string>
|
||||
|
||||
<string name="notification_clear_text">Tüm bildirimlerinizi kalıcı olarak silmek istediğinizden emin misiniz\?</string>
|
||||
<string name="notification_clear_text">Tüm bildirimleri kalıcı olarak silmek istediğinden emin misin\?</string>
|
||||
<string name="compose_preview_image_description">%s görüntüsü için eylemler</string>
|
||||
|
||||
<string name="poll_info_format"> <!-- 15 oy • 1 saat kaldı --> %1$s • %2$s</string>
|
||||
|
@ -388,8 +386,8 @@
|
|||
<string name="poll_info_closed">kapandı</string>
|
||||
<string name="poll_vote">Oy</string>
|
||||
|
||||
<string name="poll_ended_voted">Oy verdiğiniz bir anket sona erdi</string>
|
||||
<string name="poll_ended_created">Oluşturduğunuz bir anket sona erdi</string>
|
||||
<string name="poll_ended_voted">Oy verdiğin bir anket sona erdi</string>
|
||||
<string name="poll_ended_created">Oluşturduğun bir anket sona erdi</string>
|
||||
|
||||
<plurals name="poll_timespan_days">
|
||||
<item quantity="one">%d gün</item>
|
||||
|
@ -414,7 +412,7 @@
|
|||
<string name="report_sent_success">\@%s bildirildi</string>
|
||||
<string name="hint_additional_info">Ek yorumlar</string>
|
||||
<string name="report_remote_instance">%s adresine ilet</string>
|
||||
<string name="failed_fetch_statuses">Durumlar getirilemedi</string>
|
||||
<string name="failed_fetch_statuses">İletiler alınamadı</string>
|
||||
<string name="report_description_1">"Bildirim sunucu yöneticinize gönderilecektir. Bu hesabı neden bildirdiğinizle ilgili açıklama yapabilirsiniz:"</string>
|
||||
<string name="report_description_remote_instance">Hesap başka bir sunucuda. Raporun anonim bir kopyasını da oraya gönderilsin mi\?</string>
|
||||
|
||||
|
@ -430,7 +428,7 @@
|
|||
<string name="action_bookmark">Yerimi</string>
|
||||
<string name="action_edit">Düzenle</string>
|
||||
<string name="action_delete_and_redraft">Sil ve düzenle</string>
|
||||
<string name="action_view_bookmarks">Yer imleri</string>
|
||||
<string name="action_view_bookmarks">Yerimleri</string>
|
||||
<string name="action_add_poll">Anket ekle</string>
|
||||
<string name="action_access_scheduled_toot">Zamanlanmış iletiler</string>
|
||||
<string name="action_schedule_toot">İleti zamanla</string>
|
||||
|
@ -455,6 +453,21 @@
|
|||
<string name="add_poll_choice">Seçenek ekle</string>
|
||||
<string name="poll_allow_multiple_choices">Çoklu seçim</string>
|
||||
<string name="edit_poll">Düzenle</string>
|
||||
<string name="replying_to">\@%s olarak yanıtla</string>
|
||||
<string name="replying_to">Yanıtla @%s</string>
|
||||
<string name="profile_badge_bot_text">Bot</string>
|
||||
</resources>
|
||||
<string name="confirmation_domain_unmuted">%s gizleme</string>
|
||||
|
||||
<string name="mute_domain_warning_dialog_ok">Alan adından herşeyi gizle</string>
|
||||
|
||||
<string name="gradient_for_media">Gizli medya için renkli sansür uygula</string>
|
||||
|
||||
<string name="pref_title_alway_open_spoiler">Hassas içerikleri göster</string>
|
||||
<string name="poll_info_time_absolute">bitiş %s</string>
|
||||
<string name="failed_report">Bildirilemedi</string>
|
||||
<string name="poll_new_choice_hint">Seçenek %d</string>
|
||||
<string name="post_lookup_error_format">%s ileti aranırken hata oluştu</string>
|
||||
|
||||
<string name="no_saved_status">Hiç taslağınız yok.</string>
|
||||
<string name="no_scheduled_status">Hiç planlanmış durumun yok.</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -286,8 +286,6 @@
|
|||
|
||||
<string name="state_follow_requested">已发送关注请求</string>
|
||||
|
||||
<string name="no_content">没有内容</string>
|
||||
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%d 年内</string>
|
||||
<string name="abbreviated_in_days">%d 天内</string>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<string name="error_generic">應用程式出現異常</string>
|
||||
<string name="error_network">網絡請求出錯,請檢查互聯網連接並重試</string>
|
||||
|
@ -281,8 +281,6 @@
|
|||
|
||||
<string name="state_follow_requested">已請求關注</string>
|
||||
|
||||
<string name="no_content">沒有內容</string>
|
||||
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%d 年內</string>
|
||||
<string name="abbreviated_in_days">%d 天內</string>
|
||||
|
@ -385,11 +383,11 @@
|
|||
<string name="pin_action">置頂</string>
|
||||
|
||||
<plurals name="favs">
|
||||
<item quantity="other"><b>%1$s</b> 次收藏</item>
|
||||
<item quantity="other"><b>%1$s</b> 次收藏</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="reblogs">
|
||||
<item quantity="other"><b>%s</b> 次轉嘟</item>
|
||||
<item quantity="other"><b>%s</b> 次轉嘟</item>
|
||||
</plurals>
|
||||
|
||||
<string name="title_reblogged_by">轉嘟</string>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<string name="error_generic">應用程式出現異常</string>
|
||||
<string name="error_network">網絡請求出錯,請檢查互聯網連接並重試</string>
|
||||
|
@ -281,8 +281,6 @@
|
|||
|
||||
<string name="state_follow_requested">已請求關注</string>
|
||||
|
||||
<string name="no_content">沒有內容</string>
|
||||
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%d 年內</string>
|
||||
<string name="abbreviated_in_days">%d 天內</string>
|
||||
|
@ -385,11 +383,11 @@
|
|||
<string name="pin_action">置頂</string>
|
||||
|
||||
<plurals name="favs">
|
||||
<item quantity="other"><b>%1$s</b> 次收藏</item>
|
||||
<item quantity="other"><b>%1$s</b> 次收藏</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="reblogs">
|
||||
<item quantity="other"><b>%s</b> 次轉嘟</item>
|
||||
<item quantity="other"><b>%s</b> 次轉嘟</item>
|
||||
</plurals>
|
||||
|
||||
<string name="title_reblogged_by">轉嘟</string>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<string name="error_generic">应用程序出现异常</string>
|
||||
<string name="error_network">网络请求出错,请检查互联网连接并重试</string>
|
||||
|
@ -286,8 +286,6 @@
|
|||
|
||||
<string name="state_follow_requested">已发送关注请求</string>
|
||||
|
||||
<string name="no_content">没有内容</string>
|
||||
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%d 年内</string>
|
||||
<string name="abbreviated_in_days">%d 天内</string>
|
||||
|
|
|
@ -280,8 +280,6 @@
|
|||
|
||||
<string name="state_follow_requested">已請求關注</string>
|
||||
|
||||
<string name="no_content">沒有內容</string>
|
||||
|
||||
<!--These are for timestamps on statuses. For example: "16s" or "2d"-->
|
||||
<string name="abbreviated_in_years">%d 年內</string>
|
||||
<string name="abbreviated_in_days">%d 天內</string>
|
||||
|
|
|
@ -111,7 +111,6 @@
|
|||
%1$s; %2$s; %3$s, %14$s %4$s, %5$s; %6$s, %7$s, %8$s, %9$s, %10$s; %11$s, %12$s, %13$s
|
||||
</string>
|
||||
|
||||
|
||||
<string-array name="poll_duration_names">
|
||||
<item>@string/poll_duration_5_min</item>
|
||||
<item>@string/poll_duration_30_min</item>
|
||||
|
|
|
@ -198,6 +198,152 @@ class ComposeActivityTest {
|
|||
assertEquals(activity.calculateTextLength(), additionalContent.length + (ComposeActivity.MAXIMUM_URL_LENGTH * 2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenSelectionIsEmpty_specialTextIsInsertedAtCaret() {
|
||||
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
||||
val insertText = "#"
|
||||
editor.setText("Some text")
|
||||
|
||||
for (caretIndex in listOf(9, 1, 0)) {
|
||||
editor.setSelection(caretIndex)
|
||||
activity.prependSelectedWordsWith(insertText)
|
||||
// Text should be inserted at caret
|
||||
assertEquals("Unexpected value at ${caretIndex}", insertText, editor.text.substring(caretIndex, caretIndex + insertText.length))
|
||||
|
||||
// Caret should be placed after inserted text
|
||||
assertEquals(caretIndex + insertText.length, editor.selectionStart)
|
||||
assertEquals(caretIndex + insertText.length, editor.selectionEnd)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenSelectionDoesNotIncludeWordBreak_noSpecialTextIsInserted() {
|
||||
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
||||
val insertText = "#"
|
||||
val originalText = "Some text"
|
||||
val selectionStart = 1
|
||||
val selectionEnd = 4
|
||||
editor.setText(originalText)
|
||||
editor.setSelection(selectionStart, selectionEnd) // "ome"
|
||||
activity.prependSelectedWordsWith(insertText)
|
||||
|
||||
// Text and selection should be unmodified
|
||||
assertEquals(originalText, editor.text.toString())
|
||||
assertEquals(selectionStart, editor.selectionStart)
|
||||
assertEquals(selectionEnd, editor.selectionEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenSelectionIncludesWordBreaks_startsOfAllWordsArePrepended() {
|
||||
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
||||
val insertText = "#"
|
||||
val originalText = "one two three four"
|
||||
val selectionStart = 2
|
||||
val originalSelectionEnd = 15
|
||||
val modifiedSelectionEnd = 18
|
||||
editor.setText(originalText)
|
||||
editor.setSelection(selectionStart, originalSelectionEnd) // "e two three f"
|
||||
activity.prependSelectedWordsWith(insertText)
|
||||
|
||||
// text should be inserted at word starts inside selection
|
||||
assertEquals("one #two #three #four", editor.text.toString())
|
||||
|
||||
// selection should be expanded accordingly
|
||||
assertEquals(selectionStart, editor.selectionStart)
|
||||
assertEquals(modifiedSelectionEnd, editor.selectionEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenSelectionIncludesEnd_textIsNotAppended() {
|
||||
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
||||
val insertText = "#"
|
||||
val originalText = "Some text"
|
||||
val selectionStart = 7
|
||||
val selectionEnd = 9
|
||||
editor.setText(originalText)
|
||||
editor.setSelection(selectionStart, selectionEnd) // "xt"
|
||||
activity.prependSelectedWordsWith(insertText)
|
||||
|
||||
// Text and selection should be unmodified
|
||||
assertEquals(originalText, editor.text.toString())
|
||||
assertEquals(selectionStart, editor.selectionStart)
|
||||
assertEquals(selectionEnd, editor.selectionEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenSelectionIncludesStartAndStartIsAWord_textIsPrepended() {
|
||||
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
||||
val insertText = "#"
|
||||
val originalText = "Some text"
|
||||
val selectionStart = 0
|
||||
val selectionEnd = 3
|
||||
editor.setText(originalText)
|
||||
editor.setSelection(selectionStart, selectionEnd) // "Som"
|
||||
activity.prependSelectedWordsWith(insertText)
|
||||
|
||||
// Text should be inserted at beginning
|
||||
assert(editor.text.startsWith(insertText))
|
||||
|
||||
// selection should be expanded accordingly
|
||||
assertEquals(selectionStart, editor.selectionStart)
|
||||
assertEquals(selectionEnd + insertText.length, editor.selectionEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenSelectionIncludesStartAndStartIsNotAWord_textIsNotPrepended() {
|
||||
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
||||
val insertText = "#"
|
||||
val originalText = " Some text"
|
||||
val selectionStart = 0
|
||||
val selectionEnd = 1
|
||||
editor.setText(originalText)
|
||||
editor.setSelection(selectionStart, selectionEnd) // " "
|
||||
activity.prependSelectedWordsWith(insertText)
|
||||
|
||||
// Text and selection should be unmodified
|
||||
assertEquals(originalText, editor.text.toString())
|
||||
assertEquals(selectionStart, editor.selectionStart)
|
||||
assertEquals(selectionEnd, editor.selectionEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenSelectionBeginsAtWordStart_textIsPrepended() {
|
||||
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
||||
val insertText = "#"
|
||||
val originalText = "Some text"
|
||||
val selectionStart = 5
|
||||
val selectionEnd = 9
|
||||
editor.setText(originalText)
|
||||
editor.setSelection(selectionStart, selectionEnd) // "text"
|
||||
activity.prependSelectedWordsWith(insertText)
|
||||
|
||||
// Text is prepended
|
||||
assertEquals("Some #text", editor.text.toString())
|
||||
|
||||
// Selection is expanded accordingly
|
||||
assertEquals(selectionStart, editor.selectionStart)
|
||||
assertEquals(selectionEnd + insertText.length, editor.selectionEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun whenSelectionEndsAtWordStart_textIsAppended() {
|
||||
val editor = activity.findViewById<EditText>(R.id.composeEditField)
|
||||
val insertText = "#"
|
||||
val originalText = "Some text"
|
||||
val selectionStart = 1
|
||||
val selectionEnd = 5
|
||||
editor.setText(originalText)
|
||||
editor.setSelection(selectionStart, selectionEnd) // "ome "
|
||||
activity.prependSelectedWordsWith(insertText)
|
||||
|
||||
// Text is prepended
|
||||
assertEquals("Some #text", editor.text.toString())
|
||||
|
||||
// Selection is expanded accordingly
|
||||
assertEquals(selectionStart, editor.selectionStart)
|
||||
assertEquals(selectionEnd + insertText.length, editor.selectionEnd)
|
||||
}
|
||||
|
||||
private fun clickUp() {
|
||||
val menuItem = RoboMenuItem(android.R.id.home)
|
||||
activity.onOptionsItemSelected(menuItem)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Tusky v9.0
|
||||
|
||||
- Vous pouvez désormais créer des sondages depuis Tusky
|
||||
- Vous pouvez créer des sondages depuis Tusky
|
||||
- Recherche améliorée
|
||||
- Nouvelle option dans les préférences du compte pour toujours étendre les avertissements de contenu
|
||||
- Les avatars dans le menu de navigation ont désormais une forme de
|
||||
- Il est désormais possible de signaler des utilisateurs même si ils n'ont jamais posté de status
|
||||
- Tusky refuse désormais de se connecté via les connections cleartext sur Android 6+
|
||||
- Plein de petite corrections de bugs et d'améliorations
|
||||
- Les avatars dans le menu de navigation ont désormais une forme arrondie
|
||||
- Il est désormais possible de signaler des utilisateurs même si ils n’ont jamais publié de status
|
||||
- Tusky refusera désormais de se connecter en texte clair sur Android 6+
|
||||
- Plein de petite corrections de bugs et d’améliorations
|
||||
|
|
|
@ -1 +1 @@
|
|||
En klient med stöd för flera konton på det sociala nätverket Mastodon
|
||||
En klient med stöd för flera konton för det sociala nätverket Mastodon
|
||||
|
|
Loading…
Reference in New Issue