diff --git a/README.md b/README.md
index 1be6dfd85..945aca772 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
Yuito is fork of [Tusky](https://github.com/tuskyapp/Tusky).
-Tusky is a beautiful Android client for [Mastodon](https://github.com/tootsuite/mastodon). Mastodon is a GNU social-compatible federated social network. That means not one entity controls the whole network, rather, like e-mail, volunteers and organisations operate their own independent servers, users from which can all interact with each other seamlessly.
+Tusky is a beautiful Android client for [Mastodon](https://github.com/tootsuite/mastodon). Mastodon is an ActivityPub federated social network. That means no single entity controls the whole network, rather, like e-mail, volunteers and organisations operate their own independent servers, users from which can all interact with each other seamlessly.
## Features
@@ -22,6 +22,8 @@ Tusky is a beautiful Android client for [Mastodon](https://github.com/tootsuite/
If you have any bug reports, feature requests or questions please open an issue or send us a toot at [@ars42525@odakyu.app](https://odakyu.app/@ars42525)!
+For translating Tusky into your language, visit https://weblate.tusky.app/
+
### Head of development
This app was developed by [@ars42525@odakyu.app](https://odakyu.app/@ars42525).
diff --git a/app/build.gradle b/app/build.gradle
index d0e3991ac..55c59520c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,7 +3,9 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
-def getGitSha = { ->
+apply from: "../instance-build.gradle"
+
+def getGitSha = {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD'
@@ -13,19 +15,26 @@ def getGitSha = { ->
}
android {
- compileSdkVersion 28
+ compileSdkVersion 29
defaultConfig {
applicationId 'net.accelf.yuito'
minSdkVersion 21
- targetSdkVersion 28
+ targetSdkVersion 29
versionCode 4
versionName '1.1.2'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
+ resValue "string", "app_name", APP_NAME
+
+ buildConfigField("String", "CUSTOM_LOGO_URL", "\"$CUSTOM_LOGO_URL\"")
+ buildConfigField("String", "CUSTOM_INSTANCE", "\"$CUSTOM_INSTANCE\"")
+ buildConfigField("String", "SUPPORT_ACCOUNT_URL", "\"$SUPPORT_ACCOUNT_URL\"")
+
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
+ arg("room.incremental", "true")
}
}
}
@@ -61,9 +70,6 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
- androidExtensions {
- experimental = true
- }
testOptions {
unitTests {
returnDefaultValues = true
@@ -74,7 +80,6 @@ android {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
-
packagingOptions {
// Exclude unneeded files added by libraries
exclude 'LICENSE_OFL'
@@ -94,8 +99,11 @@ project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
}
}
-ext.daggerVersion = '2.24'
+ext.roomVersion = '2.2.1'
ext.retrofitVersion = '2.6.0'
+ext.okhttpVersion = '4.2.2'
+ext.glideVersion = '4.10.0'
+ext.daggerVersion = '2.25.2'
repositories {
maven {
@@ -105,72 +113,84 @@ repositories {
// if libraries are changed here, they should also be changed in LicenseActivity
dependencies {
- implementation('com.mikepenz:materialdrawer:6.1.2@aar') {
- transitive = true
- }
- implementation 'androidx.core:core:1.0.2'
- implementation 'androidx.appcompat:appcompat:1.0.2'
- implementation 'androidx.browser:browser:1.0.0'
- implementation 'androidx.recyclerview:recyclerview:1.0.0'
- implementation 'androidx.legacy:legacy-support-v13:1.0.0'
- implementation 'com.google.android.material:material:1.1.0-alpha10'
- implementation 'androidx.exifinterface:exifinterface:1.0.0'
- implementation 'androidx.cardview:cardview:1.0.0'
- implementation 'androidx.preference:preference:1.1.0-alpha04'
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+
+ implementation "androidx.core:core-ktx:1.2.0-beta01"
+ implementation "androidx.appcompat:appcompat:1.1.0"
+ implementation "androidx.browser:browser:1.0.0"
+ implementation "androidx.recyclerview:recyclerview:1.0.0"
+ implementation "androidx.exifinterface:exifinterface:1.0.0"
+ implementation "androidx.cardview:cardview:1.0.0"
+ implementation "androidx.preference:preference:1.1.0"
+ implementation "androidx.sharetarget:sharetarget:1.0.0-beta01"
+ implementation "androidx.emoji:emoji:1.0.0"
+ implementation "androidx.emoji:emoji-appcompat:1.0.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
+ implementation "androidx.constraintlayout:constraintlayout:1.1.3"
+ implementation "androidx.paging:paging-runtime-ktx:2.1.0"
+ implementation "androidx.viewpager2:viewpager2:1.0.0-rc01"
+ implementation "androidx.room:room-runtime:$roomVersion"
+ implementation "androidx.room:room-rxjava2:$roomVersion"
+ kapt "androidx.room:room-compiler:$roomVersion"
+
+ implementation "com.google.android.material:material:1.1.0-beta01"
+
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
- implementation 'com.squareup.okhttp3:okhttp:4.2.0'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.2.0'
- implementation 'org.conscrypt:conscrypt-android:2.2.1'
- implementation 'com.github.connyduck:sparkbutton:2.0.1'
- implementation 'com.github.chrisbanes:PhotoView:2.3.0'
- implementation 'com.mikepenz:google-material-typeface:3.0.1.3.original@aar'
- implementation('com.theartofdev.edmodo:android-image-cropper:2.8.0') {
- exclude group: 'com.android.support'
- }
- implementation 'com.evernote:android-job:1.2.6'
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- // EmojiCompat
- implementation 'androidx.emoji:emoji:1.0.0'
- implementation 'androidx.emoji:emoji-appcompat:1.0.0'
- implementation 'de.c1710:filemojicompat:1.0.17'
- // architecture components
- implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
- //room
- implementation 'androidx.room:room-runtime:2.1.0'
- implementation 'androidx.legacy:legacy-support-v4:1.0.0'
- kapt 'androidx.room:room-compiler:2.1.0'
- implementation 'androidx.room:room-rxjava2:2.1.0'
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+
+ implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
+ implementation "com.squareup.okhttp3:logging-interceptor:$okhttpVersion"
+
+ implementation "org.conscrypt:conscrypt-android:2.2.1"
+
+ implementation "com.github.bumptech.glide:glide:$glideVersion"
+ implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion"
+
+ implementation "io.reactivex.rxjava2:rxjava:2.2.13"
+ implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
+ implementation "io.reactivex.rxjava2:rxkotlin:2.4.0"
+
+ implementation "com.uber.autodispose:autodispose-android-archcomponents:1.4.0"
+ implementation "com.uber.autodispose:autodispose:1.4.0"
+
implementation "com.google.dagger:dagger:$daggerVersion"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
implementation "com.google.dagger:dagger-android:$daggerVersion"
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
- testImplementation 'org.robolectric:robolectric:4.3'
- testImplementation 'org.mockito:mockito-inline:3.0.0'
- testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'
- androidTestImplementation('androidx.test.espresso:espresso-core:3.1.1', {
- exclude group: 'com.android.support', module: 'support-annotations'
+
+ implementation "com.github.connyduck:sparkbutton:2.0.1"
+
+ implementation "com.github.chrisbanes:PhotoView:2.3.0"
+
+ implementation("com.mikepenz:materialdrawer:6.1.2@aar") {
+ transitive = true
+ }
+ implementation "com.mikepenz:google-material-typeface:3.0.1.3.original@aar"
+
+ implementation("com.theartofdev.edmodo:android-image-cropper:2.8.0") {
+ exclude group: "com.android.support"
+ }
+
+ implementation "com.evernote:android-job:1.4.2"
+
+ implementation "de.c1710:filemojicompat:1.0.17"
+
+
+ testImplementation "androidx.test.ext:junit:1.1.1"
+ testImplementation "org.robolectric:robolectric:4.3.1"
+ testImplementation "org.mockito:mockito-inline:3.1.0"
+ testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
+
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.1.1", {
+ exclude group: "com.android.support", module: "support-annotations"
})
- androidTestImplementation 'android.arch.persistence.room:testing:1.1.1'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- testImplementation 'androidx.test.ext:junit:1.1.1'
- debugImplementation 'im.dino:dbinspector:3.4.1@aar'
- implementation 'io.reactivex.rxjava2:rxjava:2.2.12'
- implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
- implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
- implementation 'com.uber.autodispose:autodispose-android-archcomponents:1.4.0'
- implementation 'com.uber.autodispose:autodispose:1.4.0'
- implementation 'androidx.paging:paging-runtime-ktx:2.1.0'
+ androidTestImplementation "android.arch.persistence.room:testing:1.1.1"
+ androidTestImplementation "androidx.test.ext:junit:1.1.1"
- //Glide
- implementation 'com.github.bumptech.glide:glide:4.10.0'
- implementation 'com.github.bumptech.glide:okhttp3-integration:4.10.0'
-
- //Add some useful extensions
- implementation 'androidx.core:core-ktx:1.2.0-alpha01'
+ debugImplementation "im.dino:dbinspector:4.0.0@aar"
implementation 'net.accelf:easter:1.0.1'
}
diff --git a/app/src/blue/res/xml-v25/shortcuts.xml b/app/src/blue/res/xml-v25/shortcuts.xml
deleted file mode 100644
index d0aaa2e80..000000000
--- a/app/src/blue/res/xml-v25/shortcuts.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/green/res/xml-v25/shortcuts.xml b/app/src/green/res/xml-v25/shortcuts.xml
deleted file mode 100644
index 130274fae..000000000
--- a/app/src/green/res/xml-v25/shortcuts.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 53cf5bb6a..b76e03551 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -31,7 +31,8 @@
+ android:resource="@xml/share_shortcuts" />
+
+ android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize">
@@ -91,7 +92,8 @@
+ android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
+
+ android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize" />
@@ -153,16 +155,8 @@
+
-
-
-
-
-
{
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt
index 97f7932d4..8079717b4 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt
@@ -18,10 +18,10 @@ package com.keylesspalace.tusky
import android.animation.ArgbEvaluator
import android.content.Context
import android.content.Intent
+import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.PorterDuff
import android.os.Bundle
-import android.preference.PreferenceManager
import android.view.Menu
import android.view.MenuItem
import android.view.View
@@ -35,13 +35,18 @@ import androidx.core.content.ContextCompat
import androidx.emoji.text.EmojiCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
+import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.viewpager2.widget.MarginPageTransformer
import com.bumptech.glide.Glide
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.CollapsingToolbarLayout
import com.google.android.material.floatingactionbutton.FloatingActionButton
+import com.google.android.material.shape.MaterialShapeDrawable
+import com.google.android.material.shape.ShapeAppearanceModel
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
+import com.google.android.material.tabs.TabLayoutMediator
import com.keylesspalace.tusky.adapter.AccountFieldAdapter
import com.keylesspalace.tusky.components.report.ReportActivity
import com.keylesspalace.tusky.di.ViewModelFactory
@@ -86,8 +91,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
@ColorInt
private var toolbarColor: Int = 0
@ColorInt
- private var backgroundColor: Int = 0
- @ColorInt
private var statusBarColorTransparent: Int = 0
@ColorInt
private var statusBarColorOpaque: Int = 0
@@ -107,6 +110,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ loadResources()
makeNotificationBarTransparent()
setContentView(R.layout.activity_account)
@@ -119,7 +123,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
animateAvatar = sharedPrefs.getBoolean("animateGifAvatars", false)
hideFab = sharedPrefs.getBoolean("fabHide", false)
- loadResources()
setupToolbar()
setupTabs()
setupAccountViews()
@@ -135,8 +138,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
* Load colors and dimensions from resources
*/
private fun loadResources() {
- toolbarColor = ThemeUtils.getColor(this, R.attr.toolbar_background_color)
- backgroundColor = ThemeUtils.getColor(this, android.R.attr.colorBackground)
+ toolbarColor = ThemeUtils.getColor(this, R.attr.colorSurface)
statusBarColorTransparent = ContextCompat.getColor(this, R.color.header_background_filter)
statusBarColorOpaque = ThemeUtils.getColor(this, R.attr.colorPrimaryDark)
avatarSize = resources.getDimension(R.dimen.account_activity_avatar_size)
@@ -187,16 +189,21 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
*/
private fun setupTabs() {
// Setup the tabs and timeline pager.
- adapter = AccountPagerAdapter(supportFragmentManager, viewModel.accountId)
- val pageTitles = arrayOf(getString(R.string.title_statuses), getString(R.string.title_statuses_with_replies), getString(R.string.title_statuses_pinned), getString(R.string.title_media))
- adapter.setPageTitles(pageTitles)
- accountFragmentViewPager.pageMargin = resources.getDimensionPixelSize(R.dimen.tab_page_margin)
- val pageMarginDrawable = ThemeUtils.getDrawable(this, R.attr.tab_page_margin_drawable,
- R.drawable.tab_page_margin_dark)
- accountFragmentViewPager.setPageMarginDrawable(pageMarginDrawable)
+ adapter = AccountPagerAdapter(this, viewModel.accountId)
+
accountFragmentViewPager.adapter = adapter
accountFragmentViewPager.offscreenPageLimit = 2
- accountTabLayout.setupWithViewPager(accountFragmentViewPager)
+
+ val pageTitles = arrayOf(getString(R.string.title_statuses), getString(R.string.title_statuses_with_replies), getString(R.string.title_statuses_pinned), getString(R.string.title_media))
+
+ TabLayoutMediator(accountTabLayout, accountFragmentViewPager) {
+ tab, position ->
+ tab.text = pageTitles[position]
+ }.attach()
+
+ val pageMargin = resources.getDimensionPixelSize(R.dimen.tab_page_margin)
+ accountFragmentViewPager.setPageTransformer(MarginPageTransformer(pageMargin))
+
accountTabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
tab?.position?.let { position ->
@@ -211,9 +218,6 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
})
}
- /**
- * Setup toolbar
- */
private fun setupToolbar() {
// set toolbar top margin according to system window insets
accountCoordinatorLayout.setOnApplyWindowInsetsListener { _, insets ->
@@ -236,6 +240,23 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
ThemeUtils.setDrawableTint(this, accountToolbar.navigationIcon, R.attr.account_toolbar_icon_tint_uncollapsed)
ThemeUtils.setDrawableTint(this, accountToolbar.overflowIcon, R.attr.account_toolbar_icon_tint_uncollapsed)
+ val appBarElevation = resources.getDimension(R.dimen.actionbar_elevation)
+
+ val toolbarBackground = MaterialShapeDrawable.createWithElevationOverlay(this, appBarElevation)
+ toolbarBackground.fillColor = ColorStateList.valueOf(Color.TRANSPARENT)
+ accountToolbar.background = toolbarBackground
+
+ accountHeaderInfoContainer.background = MaterialShapeDrawable.createWithElevationOverlay(this, appBarElevation)
+
+ val avatarBackground = MaterialShapeDrawable.createWithElevationOverlay(this, appBarElevation).apply {
+ fillColor = ColorStateList.valueOf(toolbarColor)
+ elevation = appBarElevation
+ shapeAppearanceModel = ShapeAppearanceModel.builder()
+ .setAllCornerSizes(resources.getDimension(R.dimen.account_avatar_background_radius))
+ .build()
+ }
+ accountAvatarImageView.background = avatarBackground
+
// Add a listener to change the toolbar icon color when it enters/exits its collapsed state.
accountAppBarLayout.addOnOffsetChangedListener(object : AppBarLayout.OnOffsetChangedListener {
@@ -281,16 +302,14 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
accountAvatarImageView.visible(scaledAvatarSize > 0)
- var transparencyPercent = abs(verticalOffset) / titleVisibleHeight.toFloat()
- if (transparencyPercent > 1) transparencyPercent = 1f
+ val transparencyPercent = (abs(verticalOffset) / titleVisibleHeight.toFloat()).coerceAtMost(1f)
window.statusBarColor = argbEvaluator.evaluate(transparencyPercent, statusBarColorTransparent, statusBarColorOpaque) as Int
val evaluatedToolbarColor = argbEvaluator.evaluate(transparencyPercent, Color.TRANSPARENT, toolbarColor) as Int
- val evaluatedTabBarColor = argbEvaluator.evaluate(transparencyPercent, backgroundColor, toolbarColor) as Int
- accountToolbar.setBackgroundColor(evaluatedToolbarColor)
- accountHeaderInfoContainer.setBackgroundColor(evaluatedTabBarColor)
- accountTabLayout.setBackgroundColor(evaluatedTabBarColor)
+
+ toolbarBackground.fillColor = ColorStateList.valueOf(evaluatedToolbarColor)
+
swipeToRefreshLayout.isEnabled = verticalOffset == 0
}
})
@@ -300,7 +319,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI
private fun makeNotificationBarTransparent() {
val decorView = window.decorView
decorView.systemUiVisibility = decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- window.statusBarColor = Color.TRANSPARENT
+ window.statusBarColor = statusBarColorTransparent
}
/**
diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
index 6b2fd2744..9477b8440 100644
--- a/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/AccountsInListFragment.kt
@@ -17,13 +17,13 @@
package com.keylesspalace.tusky
import android.os.Bundle
-import android.preference.PreferenceManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.DialogFragment
+import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.ListAdapter
@@ -35,7 +35,6 @@ import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
import com.keylesspalace.tusky.viewmodel.State
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from
-import com.uber.autodispose.autoDisposable
import com.uber.autodispose.autoDispose
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.android.extensions.LayoutContainer
diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
index 389a745e6..7cfe6fc61 100644
--- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java
@@ -23,7 +23,6 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
@@ -34,6 +33,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
+import androidx.preference.PreferenceManager;
import com.google.android.material.snackbar.Snackbar;
import com.keylesspalace.tusky.adapter.AccountSelectionAdapter;
@@ -52,8 +52,6 @@ import javax.inject.Inject;
public abstract class BaseActivity extends AppCompatActivity implements Injectable {
- @Inject
- public ThemeUtils themeUtils;
@Inject
public AccountManager accountManager;
@@ -75,8 +73,6 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
setTheme(R.style.TuskyBlackTheme);
}
- themeUtils.setAppNightMode(theme, this);
-
/* set the taskdescription programmatically, the theme would turn it blue */
String appName = getString(R.string.app_name);
Bitmap appIcon = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
diff --git a/app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt b/app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt
index f891c2366..416087a9e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt
@@ -19,6 +19,7 @@ import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
+import android.widget.Toast
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import com.google.android.material.bottomsheet.BottomSheetBehavior
@@ -52,7 +53,7 @@ abstract class BottomSheetActivity : BaseActivity() {
val bottomSheetLayout: LinearLayout = findViewById(R.id.item_status_bottom_sheet)
bottomSheet = BottomSheetBehavior.from(bottomSheetLayout)
bottomSheet.state = BottomSheetBehavior.STATE_HIDDEN
- bottomSheet.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
+ bottomSheet.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
cancelActiveSearch()
@@ -64,7 +65,7 @@ abstract class BottomSheetActivity : BaseActivity() {
}
- open fun viewUrl(url: String, text: String) {
+ open fun viewUrl(url: String, text: String, lookupFallbackBehavior: PostLookupFallbackBehavior = PostLookupFallbackBehavior.OPEN_IN_BROWSER) {
if (forceBrowser.contains(text)) {
openLink(url)
return
@@ -95,11 +96,11 @@ abstract class BottomSheetActivity : BaseActivity() {
return@subscribe
}
- openLink(url)
+ performUrlFallbackAction(url, lookupFallbackBehavior)
}, {
if (!getCancelSearchRequested(url)) {
onEndSearch(url)
- openLink(url)
+ performUrlFallbackAction(url, lookupFallbackBehavior)
}
})
@@ -120,6 +121,13 @@ abstract class BottomSheetActivity : BaseActivity() {
startActivityWithSlideInAnimation(intent)
}
+ protected open fun performUrlFallbackAction(url: String, fallbackBehavior: PostLookupFallbackBehavior) {
+ when (fallbackBehavior) {
+ PostLookupFallbackBehavior.OPEN_IN_BROWSER -> openLink(url)
+ PostLookupFallbackBehavior.DISPLAY_ERROR -> Toast.makeText(this, getString(R.string.post_lookup_error_format, url), Toast.LENGTH_SHORT).show()
+ }
+ }
+
@VisibleForTesting
fun onBeginSearch(url: String) {
searchUrl = url
@@ -201,3 +209,8 @@ fun looksLikeMastodonUrl(urlString: String): Boolean {
path.matches("^[^@]+@[^@]+$".toRegex())
}
+
+enum class PostLookupFallbackBehavior {
+ OPEN_IN_BROWSER,
+ DISPLAY_ERROR,
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt b/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt
index ea2aef639..7deb2dd7f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/LoginActivity.kt
@@ -26,9 +26,9 @@ import android.text.method.LinkMovementMethod
import android.util.Log
import android.view.MenuItem
import android.view.View
-import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
+import com.bumptech.glide.Glide
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.AccessToken
import com.keylesspalace.tusky.entity.AppCredentials
@@ -48,9 +48,6 @@ class LoginActivity : BaseActivity(), Injectable {
lateinit var mastodonApi: MastodonApi
private lateinit var preferences: SharedPreferences
- private var domain: String = ""
- private var clientId: String? = null
- private var clientSecret: String? = null
private val oauthRedirectUri: String
get() {
@@ -64,10 +61,16 @@ class LoginActivity : BaseActivity(), Injectable {
setContentView(R.layout.activity_login)
- if (savedInstanceState != null) {
- domain = savedInstanceState.getString(DOMAIN)!!
- clientId = savedInstanceState.getString(CLIENT_ID)
- clientSecret = savedInstanceState.getString(CLIENT_SECRET)
+ if(savedInstanceState == null && BuildConfig.CUSTOM_INSTANCE.isNotBlank() && !isAdditionalLogin()) {
+ domainEditText.setText(BuildConfig.CUSTOM_INSTANCE)
+ domainEditText.setSelection(BuildConfig.CUSTOM_INSTANCE.length)
+ }
+
+ if(BuildConfig.CUSTOM_LOGO_URL.isNotBlank()) {
+ Glide.with(loginLogo)
+ .load(BuildConfig.CUSTOM_LOGO_URL)
+ .placeholder(null)
+ .into(loginLogo)
}
preferences = getSharedPreferences(
@@ -113,13 +116,6 @@ class LoginActivity : BaseActivity(), Injectable {
return super.onOptionsItemSelected(item)
}
- override fun onSaveInstanceState(outState: Bundle) {
- outState.putString(DOMAIN, domain)
- outState.putString(CLIENT_ID, clientId)
- outState.putString(CLIENT_SECRET, clientSecret)
- super.onSaveInstanceState(outState)
- }
-
/**
* Obtain the oauth client credentials for this app. This is only necessary the first time the
* app is run on a given server instance. So, after the first authentication, they are
@@ -129,7 +125,7 @@ class LoginActivity : BaseActivity(), Injectable {
loginButton.isEnabled = false
- domain = canonicalizeDomain(domainEditText.text.toString())
+ val domain = canonicalizeDomain(domainEditText.text.toString())
try {
HttpUrl.Builder().host(domain).scheme("https").build()
@@ -150,10 +146,16 @@ class LoginActivity : BaseActivity(), Injectable {
return
}
val credentials = response.body()
- clientId = credentials!!.clientId
- clientSecret = credentials.clientSecret
+ val clientId = credentials!!.clientId
+ val clientSecret = credentials.clientSecret
- redirectUserToAuthorizeAndLogin(domainEditText)
+ preferences.edit()
+ .putString("domain", domain)
+ .putString("clientId", clientId)
+ .putString("clientSecret", clientSecret)
+ .apply()
+
+ redirectUserToAuthorizeAndLogin(domain, clientId)
}
override fun onFailure(call: Call, t: Throwable) {
@@ -166,22 +168,22 @@ class LoginActivity : BaseActivity(), Injectable {
mastodonApi
.authenticateApp(domain, getString(R.string.app_name), oauthRedirectUri,
- OAUTH_SCOPES, getString(R.string.app_website))
+ OAUTH_SCOPES, getString(R.string.tusky_website))
.enqueue(callback)
setLoading(true)
}
- private fun redirectUserToAuthorizeAndLogin(editText: EditText) {
+ private fun redirectUserToAuthorizeAndLogin(domain: String, clientId: String) {
/* To authorize this app and log in it's necessary to redirect to the domain given,
- * activity_login there, and the server will redirect back to the app with its response. */
+ * login there, and the server will redirect back to the app with its response. */
val endpoint = MastodonApi.ENDPOINT_AUTHORIZE
- val redirectUri = oauthRedirectUri
- val parameters = HashMap()
- parameters["client_id"] = clientId!!
- parameters["redirect_uri"] = redirectUri
- parameters["response_type"] = "code"
- parameters["scope"] = OAUTH_SCOPES
+ val parameters = mapOf(
+ "client_id" to clientId,
+ "redirect_uri" to oauthRedirectUri,
+ "response_type" to "code",
+ "scope" to OAUTH_SCOPES
+ )
val url = "https://" + domain + endpoint + "?" + toQueryString(parameters)
val uri = Uri.parse(url)
if (!openInCustomTab(uri, this)) {
@@ -189,21 +191,12 @@ class LoginActivity : BaseActivity(), Injectable {
if (viewIntent.resolveActivity(packageManager) != null) {
startActivity(viewIntent)
} else {
- editText.error = getString(R.string.error_no_web_browser_found)
+ domainEditText.error = getString(R.string.error_no_web_browser_found)
setLoading(false)
}
}
}
- override fun onStop() {
- super.onStop()
- preferences.edit()
- .putString("domain", domain)
- .putString("clientId", clientId)
- .putString("clientSecret", clientSecret)
- .apply()
- }
-
override fun onStart() {
super.onStart()
/* Check if we are resuming during authorization by seeing if the intent contains the
@@ -216,14 +209,12 @@ class LoginActivity : BaseActivity(), Injectable {
val code = uri.getQueryParameter("code")
val error = uri.getQueryParameter("error")
- /* During the redirect roundtrip this Activity usually dies, which wipes out the
- * instance variables, so they have to be recovered from where they were saved in
- * SharedPreferences. */
- domain = preferences.getNonNullString(DOMAIN, "")
- clientId = preferences.getString(CLIENT_ID, null)
- clientSecret = preferences.getString(CLIENT_SECRET, null)
+ /* restore variables from SharedPreferences */
+ val domain = preferences.getNonNullString(DOMAIN, "")
+ val clientId = preferences.getNonNullString(CLIENT_ID, "")
+ val clientSecret = preferences.getNonNullString(CLIENT_SECRET, "")
- if (code != null && domain.isNotEmpty() && !clientId.isNullOrEmpty() && !clientSecret.isNullOrEmpty()) {
+ if (code != null && domain.isNotEmpty() && clientId.isNotEmpty() && clientSecret.isNotEmpty()) {
setLoading(true)
/* Since authorization has succeeded, the final step to log in is to exchange
@@ -231,7 +222,7 @@ class LoginActivity : BaseActivity(), Injectable {
val callback = object : Callback {
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
- onLoginSuccess(response.body()!!.accessToken)
+ onLoginSuccess(response.body()!!.accessToken, domain)
} else {
setLoading(false)
domainTextInputLayout.error = getString(R.string.error_retrieving_oauth_token)
@@ -250,7 +241,7 @@ class LoginActivity : BaseActivity(), Injectable {
}
}
- mastodonApi.fetchOAuthToken(domain, clientId!!, clientSecret!!, redirectUri, code,
+ mastodonApi.fetchOAuthToken(domain, clientId, clientSecret, redirectUri, code,
"authorization_code").enqueue(callback)
} else if (error != null) {
/* Authorization failed. Put the error response where the user can read it and they
@@ -286,7 +277,7 @@ class LoginActivity : BaseActivity(), Injectable {
return intent.getBooleanExtra(LOGIN_MODE, false)
}
- private fun onLoginSuccess(accessToken: String) {
+ private fun onLoginSuccess(accessToken: String, domain: String) {
setLoading(true)
@@ -351,7 +342,7 @@ class LoginActivity : BaseActivity(), Injectable {
.setToolbarColor(toolbarColor)
.build()
try {
- customTabsIntent.launchUrl(context, uri)
+ customTabsIntent.launchUrl(context, uri)
} catch (e: ActivityNotFoundException) {
Log.w(TAG, "Activity was not found for intent $customTabsIntent")
return false
diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java
index 13037abc9..6d6d25481 100644
--- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.java
+++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.java
@@ -22,12 +22,10 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.preference.PreferenceManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
@@ -35,14 +33,18 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
+import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.emoji.text.EmojiCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
-import androidx.viewpager.widget.ViewPager;
+import androidx.preference.PreferenceManager;
+import androidx.viewpager2.widget.MarginPageTransformer;
+import androidx.viewpager2.widget.ViewPager2;
import com.bumptech.glide.Glide;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.tabs.TabLayout;
+import com.google.android.material.tabs.TabLayoutMediator;
import com.keylesspalace.tusky.appstore.CacheUpdater;
import com.keylesspalace.tusky.appstore.DrawerFooterClickedEvent;
import com.keylesspalace.tusky.appstore.EventHub;
@@ -58,7 +60,7 @@ import com.keylesspalace.tusky.interfaces.ReselectableFragment;
import com.keylesspalace.tusky.pager.MainPagerAdapter;
import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.NotificationHelper;
-import com.keylesspalace.tusky.util.ThemeUtils;
+import com.keylesspalace.tusky.util.ShareShortcutHelper;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.materialdrawer.AccountHeader;
import com.mikepenz.materialdrawer.AccountHeaderBuilder;
@@ -121,7 +123,7 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
private AccountHeader headerResult;
private Drawer drawer;
private TabLayout tabLayout;
- private ViewPager viewPager;
+ private ViewPager2 viewPager;
private SharedPreferences defPrefs;
private int notificationTabPosition;
@@ -149,7 +151,18 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
boolean showNotificationTab = false;
if (intent != null) {
+
+ /** there are two possibilities the accountId can be passed to MainActivity:
+ - from our code as long 'account_id'
+ - from share shortcuts as String 'android.intent.extra.shortcut.ID'
+ */
long accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1);
+ if(accountId == -1) {
+ String accountIdString = intent.getStringExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID);
+ if(accountIdString != null) {
+ accountId = Long.parseLong(accountIdString);
+ }
+ }
boolean accountRequested = (accountId != -1);
if (accountRequested) {
@@ -187,7 +200,6 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
setContentView(R.layout.activity_main);
composeButton = findViewById(R.id.floating_btn);
- ImageButton drawerToggle = findViewById(R.id.drawer_toggle);
tabLayout = findViewById(R.id.tab_layout);
viewPager = findViewById(R.id.pager);
@@ -199,10 +211,6 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
setupDrawer();
- // Setup the navigation drawer toggle button.
- ThemeUtils.setDrawableTint(this, drawerToggle.getDrawable(), R.attr.toolbar_icon_tint);
- drawerToggle.setOnClickListener(v -> drawer.openDrawer());
-
/* Fetch user info while we're doing other things. This has to be done after setting up the
* drawer, though, because its callback touches the header in the drawer. */
fetchUserInfo();
@@ -212,10 +220,7 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
defPrefs = PreferenceManager.getDefaultSharedPreferences(this);
int pageMargin = getResources().getDimensionPixelSize(R.dimen.tab_page_margin);
- viewPager.setPageMargin(pageMargin);
- Drawable pageMarginDrawable = ThemeUtils.getDrawable(this, R.attr.tab_page_margin_drawable,
- R.drawable.tab_page_margin_dark);
- viewPager.setPageMarginDrawable(pageMarginDrawable);
+ viewPager.setPageTransformer(new MarginPageTransformer(pageMargin));
if (defPrefs.getBoolean("viewPagerOffScreenLimit", false)) {
viewPager.setOffscreenPageLimit(9);
}
@@ -349,7 +354,7 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
if (intent != null) {
String statusUrl = intent.getStringExtra(STATUS_URL);
if (statusUrl != null) {
- viewUrl(statusUrl, statusUrl);
+ viewUrl(statusUrl, statusUrl, PostLookupFallbackBehavior.DISPLAY_ERROR);
}
}
}
@@ -439,6 +444,7 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
.withHasStableIds(true)
.withSelectedItem(-1)
.withDrawerItems(listItems)
+ .withToolbar(findViewById(R.id.main_toolbar))
.withOnDrawerItemClickListener((view, position, drawerItem) -> {
if (drawerItem != null) {
long drawerItemIdentifier = drawerItem.getIdentifier();
@@ -534,10 +540,11 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
private void setupTabs(boolean selectNotificationTab) {
List tabs = accountManager.getActiveAccount().getTabPreferences();
- adapter = new MainPagerAdapter(tabs, getSupportFragmentManager());
+ adapter = new MainPagerAdapter(tabs, this);
viewPager.setAdapter(adapter);
- tabLayout.setupWithViewPager(viewPager);
+ new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> { }).attach();
+
tabLayout.removeAllTabs();
for (int i = 0; i < tabs.size(); i++) {
TabLayout.Tab tab = tabLayout.newTab()
@@ -610,6 +617,7 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
NotificationHelper.deleteNotificationChannelsForAccount(accountManager.getActiveAccount(), MainActivity.this);
cacheUpdater.clearForUser(activeAccount.getId());
conversationRepository.deleteCacheForAccount(activeAccount.getId());
+ ShareShortcutHelper.removeShortcut(this, activeAccount);
AccountEntity newAccount = accountManager.logActiveAccountOut();
@@ -667,6 +675,8 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
updateProfiles();
+ ShareShortcutHelper.updateShortcut(this, accountManager.getActiveAccount());
+
}
private void updateProfiles() {
diff --git a/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt b/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt
index f017f3b4e..0ab7477c7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt
@@ -19,11 +19,10 @@ import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
-import android.preference.PreferenceManager
import android.util.Log
import android.view.MenuItem
-import androidx.appcompat.app.AppCompatDelegate
import androidx.fragment.app.Fragment
+import androidx.preference.PreferenceManager
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
import com.keylesspalace.tusky.fragment.preference.*
@@ -123,18 +122,11 @@ class PreferencesActivity : BaseActivity(), SharedPreferences.OnSharedPreference
"appTheme" -> {
val theme = sharedPreferences.getNonNullString("appTheme", ThemeUtils.APP_THEME_DEFAULT)
Log.d("activeTheme", theme)
- themeUtils.setAppNightMode(theme, this)
+ ThemeUtils.setAppNightMode(theme)
restartActivitiesOnExit = true
this.restartCurrentActivity()
- // MODE_NIGHT_FOLLOW_SYSTEM workaround part 2 :/
- when(theme){
- ThemeUtils.THEME_SYSTEM -> {
- AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
- }
- }
- //workaround end
}
"statusTextSize", "absoluteTimeView", "showBotOverlay", "animateGifAvatars", "viewPagerOffScreenLimit" -> {
restartActivitiesOnExit = true
diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
index 39c21cdc1..915b835f5 100644
--- a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
+++ b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
@@ -17,10 +17,11 @@ package com.keylesspalace.tusky;
import android.app.Application;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.Configuration;
-import android.preference.PreferenceManager;
import androidx.emoji.text.EmojiCompat;
+import androidx.preference.PreferenceManager;
import androidx.room.Room;
import com.evernote.android.job.JobManager;
@@ -30,6 +31,7 @@ import com.keylesspalace.tusky.di.AppInjector;
import com.keylesspalace.tusky.util.EmojiCompatFont;
import com.keylesspalace.tusky.util.LocaleManager;
import com.keylesspalace.tusky.util.NotificationPullJobCreator;
+import com.keylesspalace.tusky.util.ThemeUtils;
import com.uber.autodispose.AutoDisposePlugins;
import org.conscrypt.Conscrypt;
@@ -91,6 +93,7 @@ public class TuskyApplication extends Application implements HasAndroidInjector
initAppInjector();
initEmojiCompat();
+ initNightMode();
JobManager.create(this).addJobCreator(notificationPullJobCreator);
@@ -133,6 +136,12 @@ public class TuskyApplication extends Application implements HasAndroidInjector
AppInjector.INSTANCE.init(this);
}
+ protected void initNightMode() {
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ String theme = preferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT);
+ ThemeUtils.setAppNightMode(theme);
+ }
+
public ServiceLocator getServiceLocator() {
return serviceLocator;
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt b/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
index 2791ba2f1..66bf8e8df 100644
--- a/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/ViewMediaActivity.kt
@@ -37,9 +37,10 @@ import android.view.View
import android.webkit.MimeTypeMap
import android.widget.Toast
import androidx.core.content.FileProvider
+import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
-import androidx.viewpager.widget.PagerAdapter
-import androidx.viewpager.widget.ViewPager
+import androidx.viewpager2.adapter.FragmentStateAdapter
+import androidx.viewpager2.widget.ViewPager2
import com.bumptech.glide.Glide
import com.bumptech.glide.request.FutureTarget
import com.keylesspalace.tusky.BuildConfig.APPLICATION_ID
@@ -110,23 +111,23 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
// Adapter is actually of existential type PageAdapter & SharedElementsTransitionListener
// but it cannot be expressed and if I don't specify type explicitly compilation fails
// (probably a bug in compiler)
- val adapter: PagerAdapter = if (attachments != null) {
+ val adapter: ViewMediaAdapter = if (attachments != null) {
val realAttachs = attachments!!.map(AttachmentViewData::attachment)
// Setup the view pager.
- ImagePagerAdapter(supportFragmentManager, realAttachs, initialPosition)
+ ImagePagerAdapter(this, realAttachs, initialPosition)
} else {
val avatarUrl = intent.getStringExtra(EXTRA_AVATAR_URL)
?: throw IllegalArgumentException("attachment list or avatar url has to be set")
- AvatarImagePagerAdapter(supportFragmentManager, avatarUrl)
+ AvatarImagePagerAdapter(this, avatarUrl)
}
viewPager.adapter = adapter
- viewPager.currentItem = initialPosition
- viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
+ viewPager.setCurrentItem(initialPosition, false)
+ viewPager.registerOnPageChangeCallback(object: ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
- toolbar.title = adapter.getPageTitle(position)
+ toolbar.title = getPageTitle(position)
}
})
@@ -136,7 +137,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true)
actionBar.setDisplayShowHomeEnabled(true)
- actionBar.title = adapter.getPageTitle(initialPosition)
+ actionBar.title = getPageTitle(initialPosition)
}
toolbar.setNavigationOnClickListener { supportFinishAfterTransition() }
toolbar.setOnMenuItemClickListener { item: MenuItem ->
@@ -153,7 +154,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
window.statusBarColor = Color.BLACK
window.sharedElementEnterTransition.addListener(object : NoopTransitionListener {
override fun onTransitionEnd(transition: Transition) {
- (adapter as SharedElementTransitionListener).onTransitionEnd()
+ adapter.onTransitionEnd(viewPager.currentItem)
window.sharedElementEnterTransition.removeListener(this)
}
})
@@ -198,6 +199,13 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
.start()
}
+ private fun getPageTitle(position: Int): CharSequence {
+ if(attachments == null) {
+ return ""
+ }
+ return String.format(Locale.getDefault(), "%d/%d", position + 1, attachments?.size)
+ }
+
private fun downloadMedia() {
val url = attachments!![viewPager.currentItem].attachment.url
val filename = Uri.parse(url).lastPathSegment
@@ -227,7 +235,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
private fun copyLink() {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
- clipboard.primaryClip = ClipData.newPlainText(null, attachments!![viewPager.currentItem].attachment.url)
+ clipboard.setPrimaryClip(ClipData.newPlainText(null, attachments!![viewPager.currentItem].attachment.url))
}
private fun shareMedia() {
@@ -323,8 +331,8 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
}
}
-interface SharedElementTransitionListener {
- fun onTransitionEnd()
+abstract class ViewMediaAdapter(activity: FragmentActivity): FragmentStateAdapter(activity) {
+ abstract fun onTransitionEnd(position: Int)
}
interface NoopTransitionListener : Transition.TransitionListener {
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt
index 74beda73a..f4892f9ba 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountSelectionAdapter.kt
@@ -16,16 +16,15 @@
package com.keylesspalace.tusky.adapter
import android.content.Context
-import android.preference.PreferenceManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
+import androidx.preference.PreferenceManager
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.util.CustomEmojiHelper
import com.keylesspalace.tusky.util.loadAvatar
-
import kotlinx.android.synthetic.main.item_autocomplete_account.view.*
class AccountSelectionAdapter(context: Context) : ArrayAdapter(context, R.layout.item_autocomplete_account) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java
index 119669a99..edd93082b 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java
@@ -1,13 +1,13 @@
package com.keylesspalace.tusky.adapter;
-import androidx.recyclerview.widget.RecyclerView;
-
import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.preference.PreferenceManager;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener;
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java
index cc861df24..70a44ba8c 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/BlocksAdapter.java
@@ -15,10 +15,6 @@
package com.keylesspalace.tusky.adapter;
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-
-import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -26,6 +22,10 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener;
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java
index a82a10ea4..37f09f019 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/FollowRequestsAdapter.java
@@ -15,10 +15,6 @@
package com.keylesspalace.tusky.adapter;
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-
-import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -26,6 +22,10 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener;
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java
index 5f494658b..a7d145454 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/MutesAdapter.java
@@ -1,9 +1,5 @@
package com.keylesspalace.tusky.adapter;
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-
-import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -11,6 +7,10 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.interfaces.AccountActionListener;
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/PollAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/adapter/PollAdapter.kt
index adfc681f8..0adc0c371 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/PollAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/PollAdapter.kt
@@ -29,6 +29,7 @@ import com.keylesspalace.tusky.util.CustomEmojiHelper
import com.keylesspalace.tusky.util.HtmlUtils
import com.keylesspalace.tusky.util.visible
import com.keylesspalace.tusky.viewdata.PollOptionViewData
+import com.keylesspalace.tusky.viewdata.buildDescription
import com.keylesspalace.tusky.viewdata.calculatePercent
class PollAdapter: RecyclerView.Adapter() {
@@ -71,10 +72,7 @@ class PollAdapter: RecyclerView.Adapter() {
when(mode) {
RESULT -> {
val percent = calculatePercent(option.votesCount, voteCount)
-
- val pollOptionText = holder.resultTextView.context.getString(R.string.poll_option_format, percent, option.title)
-
- val emojifiedPollOptionText = CustomEmojiHelper.emojifyText(HtmlUtils.fromHtml(pollOptionText), emojis, holder.resultTextView)
+ val emojifiedPollOptionText = CustomEmojiHelper.emojifyText(buildDescription(option.title, percent, holder.resultTextView.context), emojis, holder.resultTextView)
holder.resultTextView.text = EmojiCompat.get().process(emojifiedPollOptionText)
val level = percent * 100
diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java
index 9a4bcbb11..fbaa49742 100644
--- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java
+++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java
@@ -57,6 +57,8 @@ import at.connyduck.sparkbutton.SparkButton;
import at.connyduck.sparkbutton.SparkEventListener;
import kotlin.collections.CollectionsKt;
+import static com.keylesspalace.tusky.viewdata.PollViewDataKt.buildDescription;
+
public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
public static class Key {
public static final String KEY_CREATED = "created";
@@ -390,7 +392,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
} else {
inactiveId = ThemeUtils.getDrawableId(reblogButton.getContext(),
R.attr.status_reblog_inactive_drawable, R.drawable.reblog_inactive_dark);
- activeId = R.drawable.reblog_active;
+ activeId = R.drawable.ic_reblog_active_24dp;
}
reblogButton.setInactiveImage(inactiveId);
reblogButton.setActiveImage(activeId);
@@ -905,10 +907,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
for (int i = 0; i < args.length; i++) {
if (i < options.size()) {
int percent = PollViewDataKt.calculatePercent(options.get(i).getVotesCount(), poll.getVotesCount());
- args[i] = HtmlUtils.fromHtml(context.getString(
- R.string.poll_option_format,
- percent,
- options.get(i).getTitle()));
+ args[i] = buildDescription(options.get(i).getTitle(), percent, context);
} else {
args[i] = "";
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java
index 4757b5676..6c1b8c6f6 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java
+++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationViewHolder.java
@@ -16,7 +16,6 @@
package com.keylesspalace.tusky.components.conversation;
import android.content.Context;
-import android.preference.PreferenceManager;
import android.text.InputFilter;
import android.text.TextUtils;
import android.view.View;
@@ -24,6 +23,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ToggleButton;
+import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import com.keylesspalace.tusky.R;
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt
index 6c73b0a79..4ac985a85 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt
@@ -17,13 +17,13 @@ package com.keylesspalace.tusky.components.conversation
import android.content.Intent
import android.os.Bundle
-import android.preference.PreferenceManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.paging.PagedList
+import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsViewModel.kt
index 515d34f0e..dd28b0cc8 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsViewModel.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsViewModel.kt
@@ -59,6 +59,7 @@ class ConversationsViewModel @Inject constructor(
}
.subscribeOn(Schedulers.io())
.doOnError { t -> Log.w("ConversationViewModel", "Failed to favourite conversation", t) }
+ .onErrorReturnItem(0)
.subscribe()
.addTo(disposables)
}
@@ -77,6 +78,7 @@ class ConversationsViewModel @Inject constructor(
}
.subscribeOn(Schedulers.io())
.doOnError { t -> Log.w("ConversationViewModel", "Failed to favourite conversation", t) }
+ .onErrorReturnItem(0)
.subscribe()
.addTo(disposables)
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt
index 6d4cc9e31..46f84ec6f 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt
@@ -16,7 +16,6 @@
package com.keylesspalace.tusky.components.report.fragments
import android.os.Bundle
-import android.preference.PreferenceManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -26,6 +25,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.paging.PagedList
+import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt
index 5b2a23dbc..394c1336e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt
@@ -23,6 +23,7 @@ import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.widget.SearchView
import androidx.lifecycle.ViewModelProviders
+import com.google.android.material.tabs.TabLayoutMediator
import com.keylesspalace.tusky.BottomSheetActivity
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.search.adapter.SearchPagerAdapter
@@ -57,9 +58,13 @@ class SearchActivity : BottomSheetActivity(), SearchView.OnQueryTextListener, Ha
}
private fun setupPages() {
- pages.adapter = SearchPagerAdapter(this, supportFragmentManager)
- tabs.setupWithViewPager(pages)
+ pages.adapter = SearchPagerAdapter(this)
pages.offscreenPageLimit = 4
+
+ TabLayoutMediator(tabs, pages) {
+ tab, position ->
+ tab.text = getPageTitle(position)
+ }.attach()
}
override fun onNewIntent(intent: Intent) {
@@ -75,9 +80,7 @@ class SearchActivity : BottomSheetActivity(), SearchView.OnQueryTextListener, Ha
.actionView as SearchView
setupSearchView(searchView)
- if (viewModel.currentQuery != null) {
- searchView.setQuery(viewModel.currentQuery, false)
- }
+ searchView.setQuery(viewModel.currentQuery, false)
return true
}
@@ -100,9 +103,19 @@ class SearchActivity : BottomSheetActivity(), SearchView.OnQueryTextListener, Ha
return false
}
+ private fun getPageTitle(position: Int): CharSequence? {
+ return when (position) {
+ 0 -> getString(R.string.title_statuses)
+ 1 -> getString(R.string.title_accounts)
+ 2 -> getString(R.string.title_hashtags_dialog)
+ 3 -> getString(R.string.title_notestock)
+ else -> throw IllegalArgumentException("Unknown page index: $position")
+ }
+ }
+
private fun handleIntent(intent: Intent) {
if (Intent.ACTION_SEARCH == intent.action) {
- viewModel.currentQuery = intent.getStringExtra(SearchManager.QUERY)
+ viewModel.currentQuery = intent.getStringExtra(SearchManager.QUERY) ?: ""
viewModel.search(viewModel.currentQuery)
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt
index 61f618ac0..11b5bccd1 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt
@@ -21,6 +21,7 @@ import com.keylesspalace.tusky.viewdata.StatusViewData
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
+import io.reactivex.rxkotlin.addTo
import javax.inject.Inject
class SearchViewModel @Inject constructor(
@@ -29,7 +30,7 @@ class SearchViewModel @Inject constructor(
private val timelineCases: TimelineCases,
private val accountManager: AccountManager) : ViewModel() {
- var currentQuery: String? = null
+ var currentQuery: String = ""
var activeAccount: AccountEntity?
get() = accountManager.activeAccount
@@ -72,7 +73,7 @@ class SearchViewModel @Inject constructor(
private val loadedStatuses = ArrayList>()
private val loadedNotestockStatuses = ArrayList>()
- fun search(query: String?) {
+ 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)!!) }
@@ -84,7 +85,7 @@ class SearchViewModel @Inject constructor(
repoResultAccount.value = accountsRepository.getSearchData(SearchType.Account, query, disposables) {
it?.accounts ?: emptyList()
}
- val hashtagQuery = if (query != null && query.startsWith("#")) query else "#$query"
+ val hashtagQuery = if (query.startsWith("#")) query else "#$query"
repoResultHashTag.value =
hashtagsRepository.getSearchData(SearchType.Hashtag, hashtagQuery, disposables) {
it?.hashtags ?: emptyList()
@@ -107,9 +108,14 @@ class SearchViewModel @Inject constructor(
fun removeItem(status: Pair) {
timelineCases.delete(status.first.id)
- .subscribe()
- if (loadedStatuses.remove(status))
- repoResultStatus.value?.refresh?.invoke()
+ .subscribe({
+ if (loadedStatuses.remove(status))
+ repoResultStatus.value?.refresh?.invoke()
+ }, {
+ err -> Log.d(TAG, "Failed to delete status", err)
+ })
+ .addTo(disposables)
+
}
fun removeNotestockItem(status: Pair) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchAccountsAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchAccountsAdapter.kt
index 8c5c84c65..918e7a427 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchAccountsAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchAccountsAdapter.kt
@@ -22,12 +22,8 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.adapter.AccountViewHolder
-import com.keylesspalace.tusky.adapter.StatusViewHolder
import com.keylesspalace.tusky.entity.Account
-import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.interfaces.LinkListener
-import com.keylesspalace.tusky.interfaces.StatusActionListener
-import com.keylesspalace.tusky.viewdata.StatusViewData
class SearchAccountsAdapter(private val linkListener: LinkListener)
: PagedListAdapter(STATUS_COMPARATOR) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchPagerAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchPagerAdapter.kt
index 94372ee57..d1518dd2d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchPagerAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchPagerAdapter.kt
@@ -15,18 +15,17 @@
package com.keylesspalace.tusky.components.search.adapter
-import android.content.Context
import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentManager
-import androidx.fragment.app.FragmentPagerAdapter
-import com.keylesspalace.tusky.R
+import androidx.fragment.app.FragmentActivity
+import androidx.viewpager2.adapter.FragmentStateAdapter
import com.keylesspalace.tusky.components.search.fragments.SearchAccountsFragment
import com.keylesspalace.tusky.components.search.fragments.SearchHashtagsFragment
import com.keylesspalace.tusky.components.search.fragments.SearchNotestockFragment
import com.keylesspalace.tusky.components.search.fragments.SearchStatusesFragment
-class SearchPagerAdapter(private val context: Context, manager: FragmentManager) : FragmentPagerAdapter(manager) {
- override fun getItem(position: Int): Fragment {
+class SearchPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
+
+ override fun createFragment(position: Int): Fragment {
return when (position) {
0 -> SearchStatusesFragment.newInstance()
1 -> SearchAccountsFragment.newInstance()
@@ -36,15 +35,6 @@ class SearchPagerAdapter(private val context: Context, manager: FragmentManager)
}
}
- override fun getPageTitle(position: Int): CharSequence? {
- return when (position) {
- 0 -> context.getString(R.string.title_statuses)
- 1 -> context.getString(R.string.title_accounts)
- 2 -> context.getString(R.string.title_hashtags_dialog)
- 3 -> context.getString(R.string.title_notestock)
- else -> throw IllegalArgumentException("Unknown page index: $position")
- }
- }
+ override fun getItemCount() = 4
- override fun getCount(): Int = 4
}
\ No newline at end of file
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt
index 1d677794f..35c5bb658 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt
@@ -28,7 +28,7 @@ import javax.inject.Inject
abstract class SearchFragment : Fragment(),
LinkListener, Injectable, SwipeRefreshLayout.OnRefreshListener {
- private var isSwipeToRefreshEnabled: Boolean = true
+
private var snackbarErrorRetry: Snackbar? = null
@Inject
lateinit var viewModelFactory: ViewModelFactory
diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt
index 230114abb..fed4c3b54 100644
--- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt
@@ -24,7 +24,6 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Environment
-import android.preference.PreferenceManager
import android.util.Log
import android.view.View
import android.widget.Toast
@@ -36,6 +35,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LiveData
import androidx.paging.PagedList
import androidx.paging.PagedListAdapter
+import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.keylesspalace.tusky.*
@@ -305,8 +305,7 @@ open class SearchStatusesFragment : SearchFragment {
val clipboard = activity!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
- val clip = ClipData.newPlainText(null, statusUrl)
- clipboard.primaryClip = clip
+ clipboard.setPrimaryClip(ClipData.newPlainText(null, statusUrl))
return@setOnMenuItemClickListener true
}
R.id.status_open_as -> {
diff --git a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt
index 1cbe2190f..bbc870614 100644
--- a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt
@@ -19,8 +19,8 @@ package com.keylesspalace.tusky.di
import android.app.Application
import android.content.Context
import android.content.SharedPreferences
-import android.preference.PreferenceManager
import androidx.localbroadcastmanager.content.LocalBroadcastManager
+import androidx.preference.PreferenceManager
import com.keylesspalace.tusky.TuskyApplication
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.EventHubImpl
diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Account.kt b/app/src/main/java/com/keylesspalace/tusky/entity/Account.kt
index 7c7c8342b..1b661bcb2 100644
--- a/app/src/main/java/com/keylesspalace/tusky/entity/Account.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/entity/Account.kt
@@ -62,8 +62,7 @@ data class Account(
if (other !is Account) {
return false
}
- val account = other as Account?
- return account?.id == this.id
+ return other.id == this.id
}
fun deepEquals(other: Account): Boolean {
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountMediaFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountMediaFragment.kt
index 3415b3400..06073d86d 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountMediaFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountMediaFragment.kt
@@ -81,7 +81,6 @@ class AccountMediaFragment : BaseFragment(), RefreshableFragment, Injectable {
private var currentCall: Call>? = null
private val statuses = mutableListOf()
private var fetchingStatus = FetchingStatus.NOT_FETCHING
- private var isVisibleToUser: Boolean = false
private lateinit var accountId: String
@@ -216,7 +215,7 @@ class AccountMediaFragment : BaseFragment(), RefreshableFragment, Injectable {
}
})
- if (isVisibleToUser) doInitialLoadingIfNeeded()
+ doInitialLoadingIfNeeded()
}
private fun refresh() {
@@ -235,14 +234,6 @@ class AccountMediaFragment : BaseFragment(), RefreshableFragment, Injectable {
topProgressBar?.show()
}
- // That's sort of an optimization to only load media once user has opened the tab
- // Attention: can be called before *any* lifecycle method!
- override fun setUserVisibleHint(isVisibleToUser: Boolean) {
- super.setUserVisibleHint(isVisibleToUser)
- this.isVisibleToUser = isVisibleToUser
- if (isVisibleToUser && isAdded) doInitialLoadingIfNeeded()
- }
-
private fun doInitialLoadingIfNeeded() {
if (isAdded) {
statusView.hide()
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java
index ba4a1550a..0d0336307 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
@@ -39,6 +38,7 @@ import androidx.arch.core.util.Function;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.util.Pair;
import androidx.lifecycle.Lifecycle;
+import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.AsyncDifferConfig;
import androidx.recyclerview.widget.AsyncListDiffer;
import androidx.recyclerview.widget.DiffUtil;
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java
index 6244f1687..3062869d7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java
@@ -45,6 +45,7 @@ import com.keylesspalace.tusky.BottomSheetActivity;
import com.keylesspalace.tusky.ComposeActivity;
import com.keylesspalace.tusky.MainActivity;
import com.keylesspalace.tusky.R;
+import com.keylesspalace.tusky.PostLookupFallbackBehavior;
import com.keylesspalace.tusky.ViewMediaActivity;
import com.keylesspalace.tusky.ViewTagActivity;
import com.keylesspalace.tusky.components.report.ReportActivity;
@@ -134,7 +135,7 @@ public abstract class SFragment extends BaseFragment implements Injectable {
}
public void onViewUrl(String url, String text) {
- bottomSheetActivity.viewUrl(url, text);
+ bottomSheetActivity.viewUrl(url, text, PostLookupFallbackBehavior.OPEN_IN_BROWSER);
}
protected void reply(Status status) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java
index 036935976..619b76834 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java
@@ -22,13 +22,29 @@ import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.arch.core.util.Function;
+import androidx.core.util.Pair;
+import androidx.core.widget.ContentLoadingProgressBar;
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.PreferenceManager;
+import androidx.recyclerview.widget.AsyncDifferConfig;
+import androidx.recyclerview.widget.AsyncListDiffer;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.ListUpdateCallback;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.SimpleItemAnimator;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.keylesspalace.tusky.AccountListActivity;
import com.keylesspalace.tusky.BaseActivity;
@@ -86,22 +102,6 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.arch.core.util.Function;
-import androidx.core.util.Pair;
-import androidx.core.widget.ContentLoadingProgressBar;
-import androidx.lifecycle.Lifecycle;
-import androidx.recyclerview.widget.AsyncDifferConfig;
-import androidx.recyclerview.widget.AsyncListDiffer;
-import androidx.recyclerview.widget.DiffUtil;
-import androidx.recyclerview.widget.DividerItemDecoration;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.ListUpdateCallback;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.SimpleItemAnimator;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
-
import at.connyduck.sparkbutton.helpers.Utils;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -377,7 +377,7 @@ public class TimelineFragment extends SFragment implements
Iterator> iterator = this.statuses.iterator();
while (iterator.hasNext()) {
Either item = iterator.next();
- if(item.isRight()) {
+ if (item.isRight()) {
Status status = item.asRight();
if (status.getId().length() < topId.length() || status.getId().compareTo(topId) < 0) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt
index 540469fac..5a50fd18c 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewMediaFragment.kt
@@ -18,13 +18,12 @@ package com.keylesspalace.tusky.fragment
import android.os.Bundle
import android.text.TextUtils
import android.widget.TextView
-import com.keylesspalace.tusky.SharedElementTransitionListener
import com.keylesspalace.tusky.ViewMediaActivity
import com.keylesspalace.tusky.entity.Attachment
import com.keylesspalace.tusky.util.visible
-abstract class ViewMediaFragment : BaseFragment(), SharedElementTransitionListener {
+abstract class ViewMediaFragment : BaseFragment() {
private var toolbarVisibiltyDisposable: Function0? = null
abstract fun setupMediaView(url: String, previewUrl: String?)
@@ -71,6 +70,8 @@ abstract class ViewMediaFragment : BaseFragment(), SharedElementTransitionListen
}
}
+ abstract fun onTransitionEnd()
+
protected fun finalizeViewSetup(url: String, previewUrl: String?, description: String?) {
val mediaActivity = activity as ViewMediaActivity
setupMediaView(url, previewUrl)
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java
index 2f2b948b2..65d871974 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java
@@ -19,7 +19,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -31,6 +30,7 @@ import androidx.annotation.Nullable;
import androidx.arch.core.util.Function;
import androidx.core.util.Pair;
import androidx.lifecycle.Lifecycle;
+import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/AccountPreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/AccountPreferencesFragment.kt
index 0ab9e1369..dfc44fa61 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/AccountPreferencesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/AccountPreferencesFragment.kt
@@ -92,9 +92,9 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(),
publicFiltersPreference = requirePreference("publicFilters")
threadFiltersPreference = requirePreference("threadFilters")
- notificationPreference.icon = IconicsDrawable(notificationPreference.context, GoogleMaterial.Icon.gmd_notifications).sizePx(iconSize).color(ThemeUtils.getColor(notificationPreference.context, R.attr.toolbar_icon_tint))
+ notificationPreference.icon = IconicsDrawable(notificationPreference.context, GoogleMaterial.Icon.gmd_notifications).sizePx(iconSize).color(ThemeUtils.getColor(notificationPreference.context, R.attr.preference_icon_tint))
mutedUsersPreference.icon = getTintedIcon(R.drawable.ic_mute_24dp)
- blockedUsersPreference.icon = IconicsDrawable(blockedUsersPreference.context, GoogleMaterial.Icon.gmd_block).sizePx(iconSize).color(ThemeUtils.getColor(blockedUsersPreference.context, R.attr.toolbar_icon_tint))
+ blockedUsersPreference.icon = IconicsDrawable(blockedUsersPreference.context, GoogleMaterial.Icon.gmd_block).sizePx(iconSize).color(ThemeUtils.getColor(blockedUsersPreference.context, R.attr.preference_icon_tint))
mutedDomainsPreference.icon = getTintedIcon(R.drawable.ic_mute_24dp)
notificationPreference.onPreferenceClickListener = this
@@ -289,7 +289,7 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(),
private fun getTintedIcon(iconId: Int): Drawable? {
val drawable = context?.getDrawable(iconId)
- ThemeUtils.setDrawableTint(context, drawable, R.attr.toolbar_icon_tint)
+ ThemeUtils.setDrawableTint(context, drawable, R.attr.preference_icon_tint)
return drawable
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/PreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/PreferencesFragment.kt
index ff3d3a69e..95b21d3a3 100644
--- a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/PreferencesFragment.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/PreferencesFragment.kt
@@ -39,13 +39,13 @@ class PreferencesFragment : PreferenceFragmentCompat() {
addPreferencesFromResource(R.xml.preferences)
val themePreference: Preference = requirePreference("appTheme")
- themePreference.icon = IconicsDrawable(themePreference.context, GoogleMaterial.Icon.gmd_palette).sizePx(iconSize).color(ThemeUtils.getColor(themePreference.context, R.attr.toolbar_icon_tint))
+ themePreference.icon = IconicsDrawable(themePreference.context, GoogleMaterial.Icon.gmd_palette).sizePx(iconSize).color(ThemeUtils.getColor(themePreference.context, R.attr.preference_icon_tint))
val emojiPreference: Preference = requirePreference("emojiCompat")
- emojiPreference.icon = IconicsDrawable(emojiPreference.context, GoogleMaterial.Icon.gmd_sentiment_satisfied).sizePx(iconSize).color(ThemeUtils.getColor(emojiPreference.context, R.attr.toolbar_icon_tint))
+ emojiPreference.icon = IconicsDrawable(emojiPreference.context, GoogleMaterial.Icon.gmd_sentiment_satisfied).sizePx(iconSize).color(ThemeUtils.getColor(emojiPreference.context, R.attr.preference_icon_tint))
val textSizePreference: Preference = requirePreference("statusTextSize")
- textSizePreference.icon = IconicsDrawable(textSizePreference.context, GoogleMaterial.Icon.gmd_format_size).sizePx(iconSize).color(ThemeUtils.getColor(textSizePreference.context, R.attr.toolbar_icon_tint))
+ textSizePreference.icon = IconicsDrawable(textSizePreference.context, GoogleMaterial.Icon.gmd_format_size).sizePx(iconSize).color(ThemeUtils.getColor(textSizePreference.context, R.attr.preference_icon_tint))
val timelineFilterPreferences: Preference = requirePreference("timelineFilterPreferences")
timelineFilterPreferences.setOnPreferenceClickListener {
@@ -68,11 +68,11 @@ class PreferencesFragment : PreferenceFragmentCompat() {
}
val languagePreference: Preference = requirePreference("language")
- languagePreference.icon = IconicsDrawable(languagePreference.context, GoogleMaterial.Icon.gmd_translate).sizePx(iconSize).color(ThemeUtils.getColor(languagePreference.context, R.attr.toolbar_icon_tint))
+ languagePreference.icon = IconicsDrawable(languagePreference.context, GoogleMaterial.Icon.gmd_translate).sizePx(iconSize).color(ThemeUtils.getColor(languagePreference.context, R.attr.preference_icon_tint))
val botIndicatorPreference = requirePreference("showBotOverlay")
val botDrawable = botIndicatorPreference.context.getDrawable(R.drawable.ic_bot_24dp)
- ThemeUtils.setDrawableTint(context, botDrawable, R.attr.toolbar_icon_tint)
+ ThemeUtils.setDrawableTint(context, botDrawable, R.attr.preference_icon_tint)
botIndicatorPreference.icon = botDrawable
updateStackTracePreference()
diff --git a/app/src/main/java/com/keylesspalace/tusky/pager/AccountPagerAdapter.java b/app/src/main/java/com/keylesspalace/tusky/pager/AccountPagerAdapter.java
deleted file mode 100644
index de2f05234..000000000
--- a/app/src/main/java/com/keylesspalace/tusky/pager/AccountPagerAdapter.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/* Copyright 2017 Andrew Dawson
- *
- * 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 . */
-
-package com.keylesspalace.tusky.pager;
-
-import android.util.SparseArray;
-import android.view.ViewGroup;
-
-import com.keylesspalace.tusky.fragment.AccountMediaFragment;
-import com.keylesspalace.tusky.fragment.TimelineFragment;
-import com.keylesspalace.tusky.interfaces.RefreshableFragment;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentPagerAdapter;
-
-public class AccountPagerAdapter extends FragmentPagerAdapter {
- private static final int TAB_COUNT = 4;
- private String accountId;
- private String[] pageTitles;
-
- private SparseArray fragments = new SparseArray<>(TAB_COUNT);
-
- private final Set pagesToRefresh = new HashSet<>();
-
- public AccountPagerAdapter(FragmentManager manager, String accountId) {
- super(manager);
- this.accountId = accountId;
- }
-
- public void setPageTitles(String[] titles) {
- pageTitles = titles;
- }
-
- @NonNull
- @Override
- public Fragment getItem(int position) {
- switch (position) {
- case 0: {
- return TimelineFragment.newInstance(TimelineFragment.Kind.USER, accountId,false);
- }
- case 1: {
- return TimelineFragment.newInstance(TimelineFragment.Kind.USER_WITH_REPLIES, accountId,false);
- }
- case 2: {
- return TimelineFragment.newInstance(TimelineFragment.Kind.USER_PINNED, accountId,false);
- }
- case 3: {
- return AccountMediaFragment.newInstance(accountId,false);
- }
- default: {
- throw new AssertionError("Page " + position + " is out of AccountPagerAdapter bounds");
- }
- }
- }
-
- @Override
- public int getCount() {
- return TAB_COUNT;
- }
-
- @NonNull
- @Override
- public Object instantiateItem(@NonNull ViewGroup container, int position) {
- Object fragment = super.instantiateItem(container, position);
- if (fragment instanceof Fragment)
- fragments.put(position, (Fragment) fragment);
- if (pagesToRefresh.contains(position)) {
- if (fragment instanceof RefreshableFragment)
- ((RefreshableFragment) fragment).refreshContent();
- pagesToRefresh.remove(position);
- }
- return fragment;
- }
-
- @Override
- public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
- super.destroyItem(container, position, object);
- fragments.remove(position);
- }
-
- @Override
- public CharSequence getPageTitle(int position) {
- return pageTitles[position];
- }
-
- @Nullable
- public Fragment getFragment(int position) {
- return fragments.get(position);
- }
-
- public void refreshContent(){
- for (int i=0;i. */
+
+package com.keylesspalace.tusky.pager
+
+import androidx.fragment.app.*
+
+import com.keylesspalace.tusky.fragment.AccountMediaFragment
+import com.keylesspalace.tusky.fragment.TimelineFragment
+import com.keylesspalace.tusky.interfaces.RefreshableFragment
+
+import androidx.viewpager2.adapter.FragmentStateAdapter
+import java.lang.ref.WeakReference
+
+class AccountPagerAdapter(
+ activity: FragmentActivity,
+ private val accountId: String
+) : FragmentStateAdapter(activity) {
+
+ private val fragments = MutableList?>(TAB_COUNT) { null }
+
+ override fun getItemCount() = TAB_COUNT
+
+ override fun createFragment(position: Int): Fragment {
+ val fragment: Fragment = when (position) {
+ 0 -> TimelineFragment.newInstance(TimelineFragment.Kind.USER, accountId, false)
+ 1 -> TimelineFragment.newInstance(TimelineFragment.Kind.USER_WITH_REPLIES, accountId, false)
+ 2 -> TimelineFragment.newInstance(TimelineFragment.Kind.USER_PINNED, accountId, false)
+ 3 -> AccountMediaFragment.newInstance(accountId, false)
+ else -> throw AssertionError("Page $position is out of AccountPagerAdapter bounds")
+ }
+
+ fragments[position] = WeakReference(fragment)
+ return fragment
+ }
+
+ fun getFragment(position: Int): Fragment? {
+ return fragments[position]?.get()
+ }
+
+ fun refreshContent() {
+ for (i in 0 until TAB_COUNT) {
+ val fragment = getFragment(i)
+ if (fragment != null && fragment is RefreshableFragment) {
+ (fragment as RefreshableFragment).refreshContent()
+ }
+ }
+ }
+
+ companion object {
+ private const val TAB_COUNT = 4
+ }
+}
diff --git a/app/src/main/java/com/keylesspalace/tusky/pager/AvatarImagePagerAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/pager/AvatarImagePagerAdapter.kt
index 1beab552e..a3dfcf2ab 100644
--- a/app/src/main/java/com/keylesspalace/tusky/pager/AvatarImagePagerAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/pager/AvatarImagePagerAdapter.kt
@@ -1,13 +1,16 @@
package com.keylesspalace.tusky.pager
import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentManager
-import androidx.fragment.app.FragmentPagerAdapter
-import com.keylesspalace.tusky.SharedElementTransitionListener
+import androidx.fragment.app.FragmentActivity
+import com.keylesspalace.tusky.ViewMediaAdapter
import com.keylesspalace.tusky.fragment.ViewMediaFragment
-class AvatarImagePagerAdapter(fragmentManager: FragmentManager, private val avatarUrl: String) : FragmentPagerAdapter(fragmentManager), SharedElementTransitionListener {
- override fun getItem(position: Int): Fragment {
+class AvatarImagePagerAdapter(
+ activity: FragmentActivity,
+ private val avatarUrl: String
+) : ViewMediaAdapter(activity) {
+
+ override fun createFragment(position: Int): Fragment {
return if (position == 0) {
ViewMediaFragment.newAvatarInstance(avatarUrl)
} else {
@@ -15,8 +18,8 @@ class AvatarImagePagerAdapter(fragmentManager: FragmentManager, private val avat
}
}
- override fun getCount() = 1
+ override fun getItemCount() = 1
- override fun onTransitionEnd() {
+ override fun onTransitionEnd(position: Int) {
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/pager/ImagePagerAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/pager/ImagePagerAdapter.kt
index 983770d2a..4f813d8b1 100644
--- a/app/src/main/java/com/keylesspalace/tusky/pager/ImagePagerAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/pager/ImagePagerAdapter.kt
@@ -1,53 +1,42 @@
package com.keylesspalace.tusky.pager
-import android.view.ViewGroup
import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentManager
-import androidx.fragment.app.FragmentStatePagerAdapter
-import com.keylesspalace.tusky.SharedElementTransitionListener
+import androidx.fragment.app.FragmentActivity
+import com.keylesspalace.tusky.ViewMediaAdapter
import com.keylesspalace.tusky.entity.Attachment
import com.keylesspalace.tusky.fragment.ViewMediaFragment
-import java.util.*
+import java.lang.ref.WeakReference
class ImagePagerAdapter(
- fragmentManager: FragmentManager,
+ activity: FragmentActivity,
private val attachments: List,
private val initialPosition: Int
-) : FragmentStatePagerAdapter(fragmentManager), SharedElementTransitionListener {
+) : ViewMediaAdapter(activity) {
- private var primaryItem: ViewMediaFragment? = null
private var didTransition = false
+ private val fragments = MutableList?>(attachments.size) { null }
- override fun setPrimaryItem(container: ViewGroup, position: Int, item: Any) {
- super.setPrimaryItem(container, position, item)
- this.primaryItem = item as ViewMediaFragment
- }
+ override fun getItemCount() = attachments.size
- override fun getItem(position: Int): Fragment {
- return if (position >= 0 && position < attachments.size) {
+ override fun createFragment(position: Int): Fragment {
+ if (position >= 0 && position < attachments.size) {
// Fragment should not wait for or start transition if it already happened but we
// instantiate the same fragment again, e.g. open the first photo, scroll to the
- // forth photo and then back to the first. The first fragment will trz to start the
+ // forth photo and then back to the first. The first fragment will try to start the
// transition and wait until it's over and it will never take place.
- ViewMediaFragment.newInstance(
+ val fragment = ViewMediaFragment.newInstance(
attachment = attachments[position],
shouldStartPostponedTransition = !didTransition && position == initialPosition
)
+ fragments[position] = WeakReference(fragment)
+ return fragment
} else {
throw IllegalStateException()
}
}
- override fun getCount(): Int {
- return attachments.size
- }
-
- override fun getPageTitle(position: Int): CharSequence {
- return String.format(Locale.getDefault(), "%d/%d", position + 1, attachments.size)
- }
-
- override fun onTransitionEnd() {
+ override fun onTransitionEnd(position: Int) {
this.didTransition = true
- primaryItem?.onTransitionEnd()
+ fragments[position]?.get()?.onTransitionEnd()
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/pager/MainPagerAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/pager/MainPagerAdapter.kt
index 7f0558c35..58728340e 100644
--- a/app/src/main/java/com/keylesspalace/tusky/pager/MainPagerAdapter.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/pager/MainPagerAdapter.kt
@@ -15,49 +15,23 @@
package com.keylesspalace.tusky.pager
-import android.util.SparseArray
-import android.view.ViewGroup
import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentManager
-import androidx.fragment.app.FragmentPagerAdapter
-import androidx.viewpager.widget.PagerAdapter
+import androidx.fragment.app.FragmentActivity
+import androidx.viewpager2.adapter.FragmentStateAdapter
import com.keylesspalace.tusky.TabData
+import java.lang.ref.WeakReference
-class MainPagerAdapter(val tabs: List, manager: FragmentManager) : FragmentPagerAdapter(manager) {
- private val fragments = SparseArray(tabs.size)
+class MainPagerAdapter(val tabs: List, activity: FragmentActivity) : FragmentStateAdapter(activity) {
+ private val fragments = MutableList?>(tabs.size) { null }
- override fun getItem(position: Int): Fragment {
+ override fun createFragment(position: Int): Fragment {
val tab = tabs[position]
- return tab.fragment(tab.arguments)
- }
-
- override fun getCount(): Int {
- return tabs.size
- }
-
- override fun getPageTitle(position: Int): CharSequence? {
- return null
- }
-
- override fun getItemId(position: Int): Long {
- return tabs[position].hashCode() + position.toLong()
- }
-
- override fun getItemPosition(item: Any): Int {
- return PagerAdapter.POSITION_NONE
- }
-
- override fun instantiateItem(container: ViewGroup, position: Int): Any {
- val fragment = super.instantiateItem(container, position)
- if (fragment is Fragment)
- fragments.put(position, fragment)
+ val fragment = tab.fragment(tab.arguments)
+ fragments[position] = WeakReference(fragment)
return fragment
}
- override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
- super.destroyItem(container, position, `object`)
- fragments.remove(position)
- }
+ override fun getItemCount() = tabs.size
- fun getFragment(position: Int): Fragment? = fragments[position]
+ fun getFragment(position: Int): Fragment? = fragments[position]?.get()
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt b/app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt
deleted file mode 100644
index b97ca3ee3..000000000
--- a/app/src/main/java/com/keylesspalace/tusky/service/AccountChooserService.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright 2019 Levi Bard
- *
- * 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 . */
-
-package com.keylesspalace.tusky.service
-
-import android.annotation.TargetApi
-import android.content.ComponentName
-import android.content.IntentFilter
-import android.graphics.drawable.Icon
-import android.os.Bundle
-import android.service.chooser.ChooserTarget
-import android.service.chooser.ChooserTargetService
-import android.text.TextUtils
-import com.bumptech.glide.Glide
-import com.keylesspalace.tusky.R
-import com.keylesspalace.tusky.TuskyApplication
-import com.keylesspalace.tusky.db.AccountManager
-import com.keylesspalace.tusky.di.Injectable
-import com.keylesspalace.tusky.util.NotificationHelper
-
-
-@TargetApi(23)
-class AccountChooserService : ChooserTargetService(), Injectable {
-
- // cannot inject here, it crashes on APIs < 23
- lateinit var accountManager: AccountManager
-
- override fun onCreate() {
- super.onCreate()
- accountManager = (application as TuskyApplication).serviceLocator.get(AccountManager::class.java)
- }
-
- override fun onGetChooserTargets(targetActivityName: ComponentName?, intentFilter: IntentFilter?): MutableList {
- val targets = mutableListOf()
- for (account in accountManager.getAllAccountsOrderedByActive()) {
- val icon: Icon = if (TextUtils.isEmpty(account.profilePictureUrl)) {
- Icon.createWithResource(applicationContext, R.drawable.avatar_default)
- } else {
- val bmp = Glide.with(this)
- .asBitmap()
- .load(account.profilePictureUrl)
- .error(R.drawable.avatar_default)
- .placeholder(R.drawable.avatar_default)
- .submit()
- Icon.createWithBitmap(bmp.get())
- }
- val bundle = Bundle()
- bundle.putLong(NotificationHelper.ACCOUNT_ID, account.id)
- targets.add(ChooserTarget(account.displayName, icon, 1.0f, targetActivityName, bundle))
- }
- return targets
- }
-}
diff --git a/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.java b/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.kt
similarity index 50%
rename from app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.java
rename to app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.kt
index 6aad5d228..f064089da 100644
--- a/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.java
+++ b/app/src/main/java/com/keylesspalace/tusky/service/TuskyTileService.kt
@@ -1,4 +1,4 @@
-/* Copyright 2017 Andrew Dawson
+/* Copyright 2019 Tusky Contributors
*
* This file is a part of Tusky.
*
@@ -13,29 +13,28 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see . */
-package com.keylesspalace.tusky.service;
+package com.keylesspalace.tusky.service
-import android.annotation.TargetApi;
-import android.content.Intent;
-import android.service.quicksettings.TileService;
+import android.annotation.TargetApi
+import android.content.Intent
+import android.service.quicksettings.TileService
-import com.keylesspalace.tusky.ComposeActivity;
+import com.keylesspalace.tusky.MainActivity
/**
- * Small Addition that adds in a QuickSettings tile that opens the Compose activity when clicked
- * Created by ztepps on 4/3/17.
+ * Small Addition that adds in a QuickSettings tile
+ * opens the Compose activity or shows an account selector when multiple accounts are present
*/
@TargetApi(24)
-public class TuskyTileService extends TileService {
- public TuskyTileService() {
- super();
- }
+class TuskyTileService : TileService() {
- @Override
- public void onClick() {
- Intent intent = new Intent(this, ComposeActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivityAndCollapse(intent);
+ override fun onClick() {
+ val intent = Intent(this, MainActivity::class.java).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ action = Intent.ACTION_SEND
+ type = "text/plain"
+ }
+ startActivityAndCollapse(intent)
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ImageLoadingHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/ImageLoadingHelper.kt
index 77a765a1e..1ab3e3747 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/ImageLoadingHelper.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/util/ImageLoadingHelper.kt
@@ -5,12 +5,12 @@ package com.keylesspalace.tusky.util
import android.widget.ImageView
import androidx.annotation.Px
import com.bumptech.glide.Glide
-import com.bumptech.glide.load.resource.bitmap.FitCenter
+import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.keylesspalace.tusky.R
-private val fitCenterTransformation = FitCenter()
+private val centerCropTransformation = CenterCrop()
fun loadAvatar(url: String?, imageView: ImageView, @Px radius: Int, animate: Boolean) {
@@ -23,7 +23,7 @@ fun loadAvatar(url: String?, imageView: ImageView, @Px radius: Int, animate: Boo
Glide.with(imageView)
.load(url)
.transform(
- fitCenterTransformation,
+ centerCropTransformation,
RoundedCorners(radius)
)
.placeholder(R.drawable.avatar_default)
@@ -34,7 +34,7 @@ fun loadAvatar(url: String?, imageView: ImageView, @Px radius: Int, animate: Boo
.asBitmap()
.load(url)
.transform(
- fitCenterTransformation,
+ centerCropTransformation,
RoundedCorners(radius)
)
.placeholder(R.drawable.avatar_default)
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java
index a040ff9e8..f6dd82f0a 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.java
@@ -19,7 +19,6 @@ import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
-import android.preference.PreferenceManager;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
@@ -32,6 +31,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsIntent;
+import androidx.preference.PreferenceManager;
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.entity.Status;
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt b/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt
index 3cb34e856..4a80bca20 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt
@@ -18,9 +18,8 @@ package com.keylesspalace.tusky.util
import android.content.Context
import android.content.SharedPreferences
import android.content.res.Configuration
-import android.preference.PreferenceManager
-
-import java.util.Locale
+import androidx.preference.PreferenceManager
+import java.util.*
class LocaleManager(context: Context) {
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java b/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java
index 805079a7a..4e0d298d7 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/NotificationHelper.java
@@ -69,6 +69,8 @@ import java.util.concurrent.ExecutionException;
import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers;
+import static com.keylesspalace.tusky.viewdata.PollViewDataKt.buildDescription;
+
public class NotificationHelper {
private static int notificationId = 0;
@@ -293,6 +295,7 @@ public class NotificationHelper {
.setColor(BuildConfig.DEBUG ? Color.parseColor("#19A341") : ContextCompat.getColor(context, R.color.tusky_blue))
.setGroup(account.getAccountId())
.setAutoCancel(true)
+ .setShortcutId(Long.toString(account.getId()))
.setDefaults(0); // So it doesn't ring twice, notify only in Target callback
setupPreferences(account, builder);
@@ -627,9 +630,9 @@ public class NotificationHelper {
builder.append('\n');
Poll poll = notification.getStatus().getPoll();
for(PollOption option: poll.getOptions()) {
- int percent = PollViewDataKt.calculatePercent(option.getVotesCount(), poll.getVotesCount());
- CharSequence optionText = HtmlUtils.fromHtml(context.getString(R.string.poll_option_format, percent, option.getTitle()));
- builder.append(optionText);
+ builder.append(buildDescription(option.getTitle(),
+ PollViewDataKt.calculatePercent(option.getVotesCount(), poll.getVotesCount()),
+ context));
builder.append('\n');
}
return builder.toString();
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java
index 7647c2c84..22e13e5ec 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/OkHttpUtils.java
@@ -18,7 +18,9 @@ package com.keylesspalace.tusky.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
-import android.preference.PreferenceManager;
+
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
import com.keylesspalace.tusky.BuildConfig;
@@ -26,7 +28,6 @@ import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.concurrent.TimeUnit;
-import androidx.annotation.NonNull;
import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt
new file mode 100644
index 000000000..5aef288cf
--- /dev/null
+++ b/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt
@@ -0,0 +1,102 @@
+/* Copyright 2019 Tusky Contributors
+ *
+ * This file is a part of Tusky.
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Tusky; if not,
+ * see . */
+
+@file:JvmName("ShareShortcutHelper")
+
+package com.keylesspalace.tusky.util
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.text.TextUtils
+import androidx.core.app.Person
+import androidx.core.content.pm.ShortcutInfoCompat
+import androidx.core.content.pm.ShortcutManagerCompat
+import androidx.core.graphics.drawable.IconCompat
+import com.bumptech.glide.Glide
+import com.keylesspalace.tusky.MainActivity
+import com.keylesspalace.tusky.R
+import com.keylesspalace.tusky.db.AccountEntity
+import io.reactivex.Single
+import io.reactivex.schedulers.Schedulers
+
+fun updateShortcut(context: Context, account: AccountEntity) {
+
+ Single.fromCallable {
+
+ val innerSize = context.resources.getDimensionPixelSize(R.dimen.adaptive_bitmap_inner_size)
+ val outerSize = context.resources.getDimensionPixelSize(R.dimen.adaptive_bitmap_outer_size)
+
+ val bmp = if (TextUtils.isEmpty(account.profilePictureUrl)) {
+ Glide.with(context)
+ .asBitmap()
+ .load(R.drawable.avatar_default)
+ .submit(innerSize, innerSize)
+ .get()
+ } else {
+ Glide.with(context)
+ .asBitmap()
+ .load(account.profilePictureUrl)
+ .error(R.drawable.avatar_default)
+ .submit(innerSize, innerSize)
+ .get()
+ }
+
+ // inset the loaded bitmap inside a 108dp transparent canvas so it looks good as adaptive icon
+ val outBmp = Bitmap.createBitmap(outerSize, outerSize, Bitmap.Config.ARGB_8888)
+
+ val canvas = Canvas(outBmp)
+ canvas.drawBitmap(bmp, (outerSize - innerSize).toFloat() / 2f, (outerSize - innerSize).toFloat() / 2f, null)
+
+ val icon = IconCompat.createWithAdaptiveBitmap(outBmp)
+
+ val person = Person.Builder()
+ .setIcon(icon)
+ .setName(account.displayName)
+ .setKey(account.identifier)
+ .build()
+
+ // This intent will be sent when the user clicks on one of the launcher shortcuts. Intent from share sheet will be different
+ val intent = Intent(context, MainActivity::class.java).apply {
+ action = Intent.ACTION_SEND
+ type = "text/plain"
+ putExtra(NotificationHelper.ACCOUNT_ID, account.id)
+ }
+
+ val shortcutInfo = ShortcutInfoCompat.Builder(context, account.id.toString())
+ .setIntent(intent)
+ .setCategories(setOf("com.keylesspalace.tusky.Share"))
+ .setShortLabel(account.displayName)
+ .setPerson(person)
+ .setLongLived(true)
+ .setIcon(icon)
+ .build()
+
+ ShortcutManagerCompat.addDynamicShortcuts(context, listOf(shortcutInfo))
+
+ }
+ .subscribeOn(Schedulers.io())
+ .onErrorReturnItem(false)
+ .subscribe()
+
+
+}
+
+fun removeShortcut(context: Context, account: AccountEntity) {
+
+ ShortcutManagerCompat.removeDynamicShortcuts(context, listOf(account.id.toString()))
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt
index fc0b7c9d2..85e89802a 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt
@@ -30,6 +30,7 @@ import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.entity.Status
import com.keylesspalace.tusky.view.MediaPreviewImageView
import com.keylesspalace.tusky.viewdata.PollViewData
+import com.keylesspalace.tusky.viewdata.buildDescription
import com.keylesspalace.tusky.viewdata.calculatePercent
import java.text.NumberFormat
import java.text.SimpleDateFormat
@@ -283,8 +284,8 @@ class StatusViewHelper(private val itemView: View) {
if (i < options.size) {
val percent = calculatePercent(options[i].votesCount, poll.votesCount)
- val pollOptionText = pollResults[i].context.getString(R.string.poll_option_format, percent, options[i].title)
- pollResults[i].text = CustomEmojiHelper.emojifyText(HtmlUtils.fromHtml(pollOptionText), emojis, pollResults[i])
+ val pollOptionText = buildDescription(options[i].title, percent, pollResults[i].context)
+ pollResults[i].text = CustomEmojiHelper.emojifyText(pollOptionText, emojis, pollResults[i])
pollResults[i].visibility = View.VISIBLE
val level = percent * 100
diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java
index 23034701b..53b762921 100644
--- a/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java
+++ b/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.java
@@ -29,27 +29,21 @@ import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDelegate;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
+import android.util.TypedValue;
/**
* Provides runtime compatibility to obtain theme information and re-theme views, especially where
* the ability to do so is not supported in resource files.
*/
-@Singleton
public class ThemeUtils {
- @Inject
- public ThemeUtils(){}
-
public static final String APP_THEME_DEFAULT = ThemeUtils.THEME_NIGHT;
private static final String THEME_NIGHT = "night";
public static final String THEME_DAY = "day";
private static final String THEME_BLACK = "black";
private static final String THEME_AUTO = "auto";
- public static final String THEME_SYSTEM = "auto_system";
+ private static final String THEME_SYSTEM = "auto_system";
public static Drawable getDrawable(@NonNull Context context, @AttrRes int attribute,
@DrawableRes int fallbackDrawable) {
@@ -63,8 +57,9 @@ public class ThemeUtils {
return context.getDrawable(resourceId);
}
- public static @DrawableRes int getDrawableId(@NonNull Context context, @AttrRes int attribute,
- @DrawableRes int fallbackDrawableId) {
+ @DrawableRes
+ public static int getDrawableId(@NonNull Context context, @AttrRes int attribute,
+ @DrawableRes int fallbackDrawableId) {
TypedValue value = new TypedValue();
if (context.getTheme().resolveAttribute(attribute, value, true)) {
return value.resourceId;
@@ -73,7 +68,8 @@ public class ThemeUtils {
}
}
- public static @ColorInt int getColor(@NonNull Context context, @AttrRes int attribute) {
+ @ColorInt
+ public static int getColor(@NonNull Context context, @AttrRes int attribute) {
TypedValue value = new TypedValue();
if (context.getTheme().resolveAttribute(attribute, value, true)) {
return value.data;
@@ -82,14 +78,16 @@ public class ThemeUtils {
}
}
- public static @ColorRes int getColorId(@NonNull Context context, @AttrRes int attribute) {
+ @ColorRes
+ public static int getColorId(@NonNull Context context, @AttrRes int attribute) {
TypedValue value = new TypedValue();
context.getTheme().resolveAttribute(attribute, value, true);
return value.resourceId;
}
/** this can be replaced with drawableTint in xml once minSdkVersion >= 23 */
- public static @Nullable Drawable getTintedDrawable(@NonNull Context context, @DrawableRes int drawableId, @AttrRes int colorAttr) {
+ @Nullable
+ public static Drawable getTintedDrawable(@NonNull Context context, @DrawableRes int drawableId, @AttrRes int colorAttr) {
Drawable drawable = context.getDrawable(drawableId);
if(drawable == null) {
return null;
@@ -102,30 +100,21 @@ public class ThemeUtils {
drawable.setColorFilter(getColor(context, attribute), PorterDuff.Mode.SRC_IN);
}
- public void setAppNightMode(String flavor, Context context) {
+ public static void setAppNightMode(String flavor) {
switch (flavor) {
default:
case THEME_NIGHT:
+ case THEME_BLACK:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
break;
case THEME_DAY:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
break;
- case THEME_BLACK:
- AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
- break;
case THEME_AUTO:
- AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
+ AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_TIME);
break;
case THEME_SYSTEM:
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
-
- //stupid workaround to make MODE_NIGHT_FOLLOW_SYSTEM work :(
- if((Settings.System.getInt(context.getContentResolver(), "display_night_theme", 0) == 1)) {
- AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
- } else if ((Settings.System.getInt(context.getContentResolver(), "display_night_theme", 0) == 0)) {
- AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
- }
break;
}
}
diff --git a/app/src/main/java/com/keylesspalace/tusky/view/ComposeScheduleView.java b/app/src/main/java/com/keylesspalace/tusky/view/ComposeScheduleView.java
index 8efe68639..dc58f86ec 100644
--- a/app/src/main/java/com/keylesspalace/tusky/view/ComposeScheduleView.java
+++ b/app/src/main/java/com/keylesspalace/tusky/view/ComposeScheduleView.java
@@ -120,7 +120,8 @@ public class ComposeScheduleView extends ConstraintLayout {
private void openPickDateDialog() {
long yesterday = Calendar.getInstance().getTimeInMillis() - 24 * 60 * 60 * 1000;
CalendarConstraints calendarConstraints = new CalendarConstraints.Builder()
- .setValidator(new DateValidatorPointForward(yesterday))
+ .setValidator(
+ DateValidatorPointForward.from(yesterday))
.build();
if (scheduleDateTime == null) {
scheduleDateTime = Calendar.getInstance(TimeZone.getDefault());
diff --git a/app/src/main/java/com/keylesspalace/tusky/view/ImageViewPager.java b/app/src/main/java/com/keylesspalace/tusky/view/ImageViewPager.java
deleted file mode 100644
index 22e967afb..000000000
--- a/app/src/main/java/com/keylesspalace/tusky/view/ImageViewPager.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright 2017 Andrew Dawson
- *
- * 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 . */
-
-package com.keylesspalace.tusky.view;
-
-import android.content.Context;
-import androidx.viewpager.widget.ViewPager;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-
-/**
- * This class is entirely to address a known issue with com.github.chrisbanes.photoview.PhotoView.
- * ViewPager will throw exceptions when a PhotoView is placed within it, so this subclass eats those
- * exceptions.
- */
-public class ImageViewPager extends ViewPager {
- public ImageViewPager(Context context) {
- super(context);
- }
-
- public ImageViewPager(Context context, AttributeSet attributeSet) {
- super(context, attributeSet);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- try {
- return super.onInterceptTouchEvent(ev);
- } catch (IllegalArgumentException e) {
- return false;
- }
- }
-}
diff --git a/app/src/main/java/com/keylesspalace/tusky/viewdata/PollViewData.kt b/app/src/main/java/com/keylesspalace/tusky/viewdata/PollViewData.kt
index 3b893f8b0..dff0c9f60 100644
--- a/app/src/main/java/com/keylesspalace/tusky/viewdata/PollViewData.kt
+++ b/app/src/main/java/com/keylesspalace/tusky/viewdata/PollViewData.kt
@@ -15,8 +15,13 @@
package com.keylesspalace.tusky.viewdata
+import android.content.Context
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.entity.Poll
import com.keylesspalace.tusky.entity.PollOption
+import com.keylesspalace.tusky.util.HtmlUtils
import java.util.*
import kotlin.math.roundToInt
@@ -44,6 +49,12 @@ fun calculatePercent(fraction: Int, total: Int): Int {
}
}
+fun buildDescription(title: String, percent: Int, context: Context): Spanned {
+ return SpannableStringBuilder(HtmlUtils.fromHtml(context.getString(R.string.poll_percent_format, percent)))
+ .append(" ")
+ .append(title)
+}
+
fun Poll?.toViewData(): PollViewData? {
if (this == null) return null
return PollViewData(
diff --git a/app/src/main/res/color/tab_icon_color.xml b/app/src/main/res/color/tab_icon_color.xml
deleted file mode 100644
index 8edd8d373..000000000
--- a/app/src/main/res/color/tab_icon_color.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable-night/avatar_background.xml b/app/src/main/res/drawable-night/avatar_background.xml
deleted file mode 100644
index 4fb7dbda1..000000000
--- a/app/src/main/res/drawable-night/avatar_background.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/avatar_background.xml b/app/src/main/res/drawable/avatar_background.xml
deleted file mode 100644
index 848919782..000000000
--- a/app/src/main/res/drawable/avatar_background.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_menu_24dp.xml b/app/src/main/res/drawable/ic_menu_24dp.xml
deleted file mode 100644
index 8ec2ddf73..000000000
--- a/app/src/main/res/drawable/ic_menu_24dp.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_reblog_active_24dp.xml b/app/src/main/res/drawable/ic_reblog_active_24dp.xml
new file mode 100644
index 000000000..8d28a4005
--- /dev/null
+++ b/app/src/main/res/drawable/ic_reblog_active_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_reblog_dark_18dp.xml b/app/src/main/res/drawable/ic_reblog_dark_24dp.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_reblog_dark_18dp.xml
rename to app/src/main/res/drawable/ic_reblog_dark_24dp.xml
diff --git a/app/src/main/res/drawable/ic_reblog_light_18dp.xml b/app/src/main/res/drawable/ic_reblog_light_24dp.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_reblog_light_18dp.xml
rename to app/src/main/res/drawable/ic_reblog_light_24dp.xml
diff --git a/app/src/main/res/drawable/reblog_active.xml b/app/src/main/res/drawable/reblog_active.xml
deleted file mode 100644
index d27942e55..000000000
--- a/app/src/main/res/drawable/reblog_active.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/tab_page_margin_black.xml b/app/src/main/res/drawable/tab_page_margin_black.xml
deleted file mode 100644
index a9d6d6cfa..000000000
--- a/app/src/main/res/drawable/tab_page_margin_black.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/tab_page_margin_dark.xml b/app/src/main/res/drawable/tab_page_margin_dark.xml
deleted file mode 100644
index 3bd2e0c2a..000000000
--- a/app/src/main/res/drawable/tab_page_margin_dark.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/tab_page_margin_light.xml b/app/src/main/res/drawable/tab_page_margin_light.xml
deleted file mode 100644
index bc46cd5f9..000000000
--- a/app/src/main/res/drawable/tab_page_margin_light.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout-sw640dp/fragment_timeline.xml b/app/src/main/res/layout-sw640dp/fragment_timeline.xml
index 27e983e5c..56150457d 100644
--- a/app/src/main/res/layout-sw640dp/fragment_timeline.xml
+++ b/app/src/main/res/layout-sw640dp/fragment_timeline.xml
@@ -3,8 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="?attr/tab_page_margin_drawable">
+ android:layout_height="match_parent">
+
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
\ No newline at end of file
diff --git a/app/src/main/res/layout-sw640dp/fragment_timeline_notifications.xml b/app/src/main/res/layout-sw640dp/fragment_timeline_notifications.xml
index e0d0583a5..82a13db74 100644
--- a/app/src/main/res/layout-sw640dp/fragment_timeline_notifications.xml
+++ b/app/src/main/res/layout-sw640dp/fragment_timeline_notifications.xml
@@ -3,8 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="?attr/tab_page_margin_drawable">
+ android:layout_height="match_parent">
\ No newline at end of file
diff --git a/app/src/main/res/layout-sw640dp/fragment_view_thread.xml b/app/src/main/res/layout-sw640dp/fragment_view_thread.xml
index 12a0f476e..b8e1cf9a9 100644
--- a/app/src/main/res/layout-sw640dp/fragment_view_thread.xml
+++ b/app/src/main/res/layout-sw640dp/fragment_view_thread.xml
@@ -1,20 +1,19 @@
+ android:layout_height="match_parent">
+ android:layout_gravity="center_horizontal">
diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml
index 51c889acf..254029e76 100644
--- a/app/src/main/res/layout/activity_about.xml
+++ b/app/src/main/res/layout/activity_about.xml
@@ -16,8 +16,8 @@
+ android:layout_gravity="center"
+ android:textDirection="anyRtl">
+
+
+
-
@@ -317,8 +315,10 @@
android:layout_height="?attr/actionBarSize"
android:layout_gravity="top"
android:background="@android:color/transparent"
+ app:contentInsetStartWithNavigation="0dp"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways" />
+
-
+
+
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index 06a4bf426..70c912428 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -27,6 +27,7 @@
android:layout_height="178dp"
android:layout_marginBottom="50dp"
android:contentDescription="@null"
+ android:id="@+id/loginLogo"
app:srcCompat="@drawable/elephant_friend" />
+ android:layout_weight="1">
-
+ android:layout_height="wrap_content"
+ android:elevation="@dimen/actionbar_elevation">
-
-
-
-
-
+ app:contentInsetStartWithNavigation="0dp">
-
+
+
+
+
+
+
+
-
diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml
index 992c2bd10..566e995c6 100644
--- a/app/src/main/res/layout/activity_search.xml
+++ b/app/src/main/res/layout/activity_search.xml
@@ -10,29 +10,29 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="@dimen/actionbar_elevation"
- android:stateListAnimator="@null"
app:layout_collapseMode="pin">
+
+
-
-
diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml
index 4381e5993..a4ea14020 100644
--- a/app/src/main/res/layout/fragment_search.xml
+++ b/app/src/main/res/layout/fragment_search.xml
@@ -4,20 +4,20 @@
android:id="@+id/layoutRoot"
android:layout_width="@dimen/timeline_width"
android:layout_height="match_parent"
- android:background="?attr/tab_page_margin_drawable">
+ android:background="?attr/tab_page_margin_color">
+ android:id="@+id/swipeRefreshLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ android:id="@+id/searchRecyclerView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:background="?attr/window_background"
+ tools:listitem="@layout/item_account" />
diff --git a/app/src/main/res/layout/fragment_timeline.xml b/app/src/main/res/layout/fragment_timeline.xml
index e246ed6fd..94431fffe 100644
--- a/app/src/main/res/layout/fragment_timeline.xml
+++ b/app/src/main/res/layout/fragment_timeline.xml
@@ -3,7 +3,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:background="?attr/window_background">
+
+ tools:visibility="visible" />
+
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_timeline_notifications.xml b/app/src/main/res/layout/fragment_timeline_notifications.xml
index 6f7dfe1d2..d27c6183a 100644
--- a/app/src/main/res/layout/fragment_timeline_notifications.xml
+++ b/app/src/main/res/layout/fragment_timeline_notifications.xml
@@ -58,7 +58,8 @@
+ android:layout_height="match_parent"
+ android:background="?attr/window_background" />
diff --git a/app/src/main/res/layout/fragment_view_image.xml b/app/src/main/res/layout/fragment_view_image.xml
index 39bbd9fb6..faf1f806f 100644
--- a/app/src/main/res/layout/fragment_view_image.xml
+++ b/app/src/main/res/layout/fragment_view_image.xml
@@ -1,7 +1,7 @@
+ android:layout_gravity="center"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_view_thread.xml b/app/src/main/res/layout/fragment_view_thread.xml
index aa6877d41..a990942e3 100644
--- a/app/src/main/res/layout/fragment_view_thread.xml
+++ b/app/src/main/res/layout/fragment_view_thread.xml
@@ -9,5 +9,7 @@
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="?attr/window_background"
android:scrollbars="vertical" />
+
diff --git a/app/src/main/res/layout/fragment_view_video.xml b/app/src/main/res/layout/fragment_view_video.xml
index 0247a9cb3..083bdb20f 100644
--- a/app/src/main/res/layout/fragment_view_video.xml
+++ b/app/src/main/res/layout/fragment_view_video.xml
@@ -2,9 +2,9 @@
@@ -14,6 +14,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize"
android:background="#60000000"
+ android:hyphenationFrequency="full"
android:lineSpacingMultiplier="1.1"
android:padding="8dp"
android:textAlignment="center"
diff --git a/app/src/main/res/layout/item_follow.xml b/app/src/main/res/layout/item_follow.xml
index 1af4f06c9..bed3795e0 100644
--- a/app/src/main/res/layout/item_follow.xml
+++ b/app/src/main/res/layout/item_follow.xml
@@ -36,8 +36,9 @@
android:contentDescription="@string/action_view_profile"
android:scaleType="centerCrop"
android:textSize="?attr/status_text_medium"
+ app:layout_constraintBottom_toBottomOf="@id/notification_username"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/notification_text"
+ app:layout_constraintTop_toTopOf="@id/notification_display_name"
tools:src="@drawable/avatar_default" />
diff --git a/app/src/main/res/layout/item_status.xml b/app/src/main/res/layout/item_status.xml
index f0b4f9511..ce5beab2b 100644
--- a/app/src/main/res/layout/item_status.xml
+++ b/app/src/main/res/layout/item_status.xml
@@ -106,6 +106,7 @@
android:id="@+id/status_content_warning_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:hyphenationFrequency="full"
android:importantForAccessibility="no"
android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorPrimary"
@@ -146,6 +147,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:focusable="true"
+ android:hyphenationFrequency="full"
android:importantForAccessibility="no"
android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorPrimary"
@@ -448,7 +450,7 @@
app:layout_constraintEnd_toStartOf="@id/status_favourite"
app:layout_constraintStart_toEndOf="@id/status_reply"
app:layout_constraintTop_toTopOf="@id/status_reply"
- sparkbutton:activeImage="@drawable/reblog_active"
+ sparkbutton:activeImage="@drawable/ic_reblog_active_24dp"
sparkbutton:iconSize="28dp"
sparkbutton:inactiveImage="?attr/status_reblog_inactive_drawable"
sparkbutton:primaryColor="@color/tusky_blue"
diff --git a/app/src/main/res/layout/item_status_detailed.xml b/app/src/main/res/layout/item_status_detailed.xml
index c83bd3bad..e2a8e8d41 100644
--- a/app/src/main/res/layout/item_status_detailed.xml
+++ b/app/src/main/res/layout/item_status_detailed.xml
@@ -84,6 +84,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
+ android:hyphenationFrequency="full"
android:importantForAccessibility="no"
android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorPrimary"
@@ -120,6 +121,7 @@
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:focusable="true"
+ android:hyphenationFrequency="full"
android:importantForAccessibility="no"
android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorPrimary"
@@ -536,7 +538,7 @@
app:layout_constraintEnd_toStartOf="@id/status_favourite"
app:layout_constraintStart_toEndOf="@id/status_reply"
app:layout_constraintTop_toTopOf="@id/status_reply"
- sparkbutton:activeImage="@drawable/reblog_active"
+ sparkbutton:activeImage="@drawable/ic_reblog_active_24dp"
sparkbutton:iconSize="28dp"
sparkbutton:inactiveImage="?attr/status_reblog_inactive_drawable"
sparkbutton:primaryColor="@color/tusky_blue"
diff --git a/app/src/main/res/layout/item_status_notification.xml b/app/src/main/res/layout/item_status_notification.xml
index 08697054d..27c93ad65 100644
--- a/app/src/main/res/layout/item_status_notification.xml
+++ b/app/src/main/res/layout/item_status_notification.xml
@@ -13,8 +13,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
- android:layout_marginBottom="6dp"
android:layout_marginTop="8dp"
+ android:layout_marginBottom="6dp"
android:drawablePadding="10dp"
android:ellipsize="end"
android:gravity="center_vertical"
@@ -39,8 +39,8 @@
android:layout_alignParentStart="true"
android:ellipsize="end"
android:maxLines="1"
- android:paddingEnd="@dimen/status_display_name_padding_end"
android:paddingStart="0dp"
+ android:paddingEnd="@dimen/status_display_name_padding_end"
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
android:textColor="?android:textColorTertiary"
android:textSize="?attr/status_text_medium"
@@ -51,8 +51,8 @@
android:id="@+id/status_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_toEndOf="@id/status_display_name"
android:layout_toStartOf="@+id/status_timestamp_info"
+ android:layout_toEndOf="@id/status_display_name"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorTertiary"
@@ -77,27 +77,27 @@
android:layout_height="wrap_content"
android:layout_below="@id/status_name_bar"
android:layout_toEndOf="@id/notification_status_avatar"
+ android:hyphenationFrequency="full"
android:lineSpacingMultiplier="1.1"
android:textColor="?android:textColorTertiary"
android:textSize="?attr/status_text_medium"
tools:text="Example CW text" />
-
+ android:id="@+id/button_toggle_notification_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/notification_content"
+ android:layout_marginTop="4dp"
+ android:layout_marginBottom="4dp"
+ android:layout_toEndOf="@id/notification_status_avatar"
+ android:background="?attr/content_warning_button"
+ android:minWidth="150dp"
+ android:minHeight="0dp"
+ android:paddingLeft="16dp"
+ android:paddingTop="4dp"
+ android:paddingRight="16dp"
+ android:paddingBottom="4dp"
+ android:textAllCaps="true"
+ android:textOff="@string/status_content_show_less"
+ android:textOn="@string/status_content_show_more"
+ android:textSize="?attr/status_text_medium"
+ android:visibility="gone" />
@@ -166,7 +167,7 @@
android:id="@+id/notification_notification_avatar"
android:layout_width="24dp"
android:layout_height="24dp"
- android:layout_alignBottom="@+id/notification_status_avatar"
- android:layout_alignEnd="@id/notification_status_avatar" />
+ android:layout_alignEnd="@id/notification_status_avatar"
+ android:layout_alignBottom="@+id/notification_status_avatar" />
diff --git a/app/src/main/res/layout/toolbar_basic.xml b/app/src/main/res/layout/toolbar_basic.xml
index bda3db47b..71039105f 100644
--- a/app/src/main/res/layout/toolbar_basic.xml
+++ b/app/src/main/res/layout/toolbar_basic.xml
@@ -12,8 +12,7 @@
+ android:layout_height="?attr/actionBarSize" />
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 00e1d7bd3..1fda6854d 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -26,7 +26,6 @@
الرسائل المباشرة
الألسنة
تبويق
- #%s
المشاركات
يحتوي على ردود
مدبّس
@@ -483,4 +482,12 @@
عندما تكون الكلمة أو العبارة أبجدية رقمية فقط ، فلن يتم تطبيقها إلا إذا كانت مطابقة للكلمة بأكملها
%1$s • %2$s
-
+ التبويقات المبَرمَجة
+ تعديل
+ التبويقات المبَرمَجة
+ برمجة تبويق
+ صفّر
+ اضغط هنا لضبط برمجة التبويق.
+ خطأ أثناء البحث عن منشور %s
+
+
diff --git a/app/src/main/res/values-bn-rIN/strings.xml b/app/src/main/res/values-bn-rIN/strings.xml
index 0263e7ef8..3af47d16f 100644
--- a/app/src/main/res/values-bn-rIN/strings.xml
+++ b/app/src/main/res/values-bn-rIN/strings.xml
@@ -28,7 +28,6 @@
সরাসরি বার্তা
ট্যাবগুলি
টুট
- #%s
পোস্টগুলি
উত্তরের সাথে
পিন করা
@@ -440,7 +439,6 @@
%s বাকি
%s এ শেষ হবে
বন্ধ
- <b>%1$d%%</b> %2$s
ভোট
@@ -505,4 +503,13 @@
পছন্দ %d
সম্পাদন
+নির্ধারিত টুটগুলি
+ সম্পাদন
+ নির্ধারিত টুটগুলি
+ নির্ধারিত টুট
+ রিসেট
+ নির্ধারিত টুট কনফিগার করতে এখানে আলতো চাপুন।
+ টাস্কি দ্বারা চালিত
+ %s পোস্ট অনুসন্ধানে ত্রুটি
+
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index 36037dfbe..2b66cd7be 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -23,7 +23,6 @@
Local
Federació
Toot
- #%s
Posts
Seguits
Seguidors
@@ -465,7 +464,6 @@
Advertència: %s
- <b>%1$d%%</b> %2$s
Toot fixat
Toot no fixat
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 675cf5fd5..1d0fd5a3d 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -26,7 +26,6 @@
Přímé zprávy
Panely
Toot
- #%s
Tooty
S odpověďmi
Připnuté
@@ -392,7 +391,6 @@
zbývá %s
končí v %s
uzavřena
- <b>%1$d%%</b> %2$s
Hlasovat
@@ -466,4 +464,19 @@
Možnost %d
Upravit
+Plánované tooty
+ Upravit
+ Přidat anketu
+ Plánované tooty
+ Naplánovat toot
+ Obnovit
+ Klepnutím sem nastavíte plánovaný toot.
+ Vždy rozbalovat tooty označené varováními o obsahu
+ Celé slovo
+ Je-li klíčové slovo nebo fráze pouze alfanumerická, bude použita pouze, pokud odpovídá celému slovu
+ Účty
+ Hledání selhalo
+
+ Chyba při hledání příspěvku %s
+
diff --git a/app/src/main/res/values-cy/strings.xml b/app/src/main/res/values-cy/strings.xml
index 049d88c4c..7c9a6a954 100644
--- a/app/src/main/res/values-cy/strings.xml
+++ b/app/src/main/res/values-cy/strings.xml
@@ -278,7 +278,6 @@
Digwyddodd gwall rhwydwaith! Gwiriwch eich cysylltiad a cheisiwch eto!
Negeseuon Uniongyrchol
Tabiau
- #%s
Wedi\'i binio
Parthau cudd
Dim byd yma.
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 98bbe6c9c..3dab97d04 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -26,7 +26,6 @@
Direktnachrichten
Tabs
Unterhaltung
- #%s
Beiträge
mit Antworten
Angeheftet
@@ -376,7 +375,6 @@
%s verbleibend
endet um %s
Geschlossen
- <b>%1$d%%</b> %2$s
Abstimmen
@@ -448,4 +446,11 @@
Auswahlmöglichkeit hinzufügen
Mehrere Möglichkeiten
Möglichkeit %d
+ Geplante Beiträge
+ Editieren
+ Geplante Beiträge
+ Plane Beitrag
+ Zurücksetzen
+ Drücke hier, um den geplanten Beitrag zu konfigurieren.
+ Dies sind Zeitstempel für Status. Beispiele: \"16s\" oder \"2t\".
diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml
index 0f3e4c847..776cc95c2 100644
--- a/app/src/main/res/values-eo/strings.xml
+++ b/app/src/main/res/values-eo/strings.xml
@@ -26,7 +26,6 @@
Rektaj mesaĝoj
Langetoj
Mesaĝo
- #%s
Mesaĝoj
Kun respondoj
Alpinglitaj
@@ -391,7 +390,6 @@
%s restas
finiĝos je %s
finiĝita
- <b>%1$d%%</b> %2$s
Voĉdoni
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index ce8427a68..63f507076 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -18,15 +18,14 @@
Se requiere permiso para descargar al almacenamiento.
No se pueden adjuntar imágenes y vídeos en el mismo estado.
La subida falló.
- Error al publicar.
+ Error al enviar estado.
Inicio
Notificaciones
Local
Federada
Mensajes Directos
Pestañas
- Publicación
- #%s
+ Estado
Estados
Con respuestas
Fijado
@@ -50,8 +49,8 @@
Ocultar
Nada aquí.
Nada por aquí. ¡Arrastra hacia abajo para recargar!
- %s impulsó tu toot
- %s marcó como favorito tu post
+ %s impulsó tu estado
+ %s marcó como favorito tu estado
%s te siguió
Reportar @%s
¿Información adicional?
@@ -61,7 +60,7 @@
Favorito
Más
Redactar
- Iniciar sesión
+ Iniciar sesión con Mastodon
Cerrar sesión
¿Seguro que quiere cerrar la sesión de %1$s?
Seguir
@@ -110,7 +109,7 @@
Abrir como %s
Compartir como…
Compartir URL…
- Compartir contenido…
+ Compartir estado…
Compartir medios a…
¡Enviado!
El usuario ya no está bloqueado
@@ -143,7 +142,7 @@
Descargar
¿Cancelar petición de amistad?
¿Dejar de seguir esta cuenta?
- ¿Eliminar este toot?
+ ¿Eliminar este estado\?
Público: Mostrar en historias públicas
Oculto: No mostrar en historias públicas
Privado: Sólo visible para seguidores
@@ -260,8 +259,8 @@
Tendrá que admitir los seguidores manualmente
¿Guardar borrador?
Enviando estado…
- Error enviando estado
- Enviando estado
+ Error al enviar el estado
+ Enviando estados
Envío cancelado
Una copia del estado se ha guardado en borradores
Redactar
@@ -370,7 +369,7 @@
Descargando contenido
- ¿Borrar y devolver a borradores este toot\?
+ ¿Borrar y devolver a borradores este estado\?
encuestas que han terminado
Notificaciones sobre encuestas que han terminado
@@ -416,8 +415,6 @@
Abrir autor del impulso
Mostrar impulsos
- <b>%1$d%%</b> %2$s
-
Dominios ocultos
Dominios ocultos
Silenciar %s
@@ -445,7 +442,7 @@
La cuenta es de otro servidor. ¿Enviar una copia anónima del reporte\?
Mostrar filtro de notificaciones
-Mostrar siempre toots marcados con avisos de contenido
+Mostrar siempre estados marcados con avisos de contenido
Cuentas
Error al buscar
@@ -463,4 +460,13 @@
Opción %d
Editar
-
+Estados programados
+ Editar
+ Estados programados
+ Programar estado
+ Reiniciar
+ Pulsa aquí para configurar un estado programado.
+ Error al buscar el post %s
+
+Potenciado por Tusky
+
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index e033cacfc..1c1d143e9 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -1,8 +1,8 @@
-
+
Errorea gertatu da.
Eremu hau ezin da hutsik egon.
- Domeinu izen okerra.
+ Domeinu baliogabea sartu da
Akatsa saioa hasterakoan.
Ez da web nabigatzailerik aurkitu.
Identifikatu gabeko baimentza akatsa gertatu da.
@@ -27,7 +27,7 @@
Erantzunekin
Jarraitzen
Jarraitzaileak
- Gogokoak
+ Gogokoenak
Isilduak
Blokeatuak
Eskakizunak
@@ -99,22 +99,22 @@
Emoji teklatua
%1$s jaisten
Lotura kopiatu
- Tutaren URL-a partekatu…
+ Tutaren URLa partekatu…
Tuta partekatu…
- Partekatu multimedia hona…
+ Partekatu media hona…
Bidalia!
- Erabiltzailea ez dago blokeatuta iada.
- Iada erabiltzailea ez dago mutututa.
+ Erabiltzailea desblokeatuta
+ Erabiltzailea isil gabetua
Bidalia!
Erantzuna ongi bidali da.
- Instantzia hautatu
+ Zein instantzia\?
Zer duzu buruan?
- Eduki abisua
- Izena
+ Eduki-abisua
+ Agertuko den izena
Biografia
Bilatu…
Emaitzarik ez
- Erantzuna…
+ Erantzun…
Irudia
Goiburua
Zer da instantzia?
@@ -124,12 +124,12 @@
\n\nInstantzia zure kontua dagoen gunea da, baino beste instantzietako erabiltzaileak zurean egongo balira bezala jarraitu ditzakezu.
\n\nInformazio gehiago joinmastodon.org helbidean topatuko duzu.
- Multimedia igoera bukatzen
+ Mediaren igoera bukatzen
Igotzen…
Jaitsi
- Lagun eskaera ezeztatu?
- Kontu hau jarraitzeari utzi?
- Tuta ezabatu?
+ Jarraipen-eskaerari uko egin\?
+ Kontu honi jarraitzeari utzi\?
+ Tut hau ezabatu\?
Publikoa: Istorio publikoetan erakutsi
Ezkutukoa: Ez erakutsi istorio publikoetan
Pribatua: Jarraitzaileentzat soilik ikusgai
@@ -140,53 +140,53 @@
Soinuarekin jakinarazi
Bibrazioarekin jakinarazi
Led-arekin jakinarazi
- Noiz jakinarazi:
+ Noiz jakinarazi
Aipatzen naute
Jarraitzen didate
Bultzatzen naute
- Nire mezuak gogoko ditu
+ Nire argitarapenak gustokoak izan dira
Interfazea
- Gaia
- Denbora lerroak
+ Aplikazioaren gaia
+ Denbora-lerroak
Iluna
Argia
Beltza
- Automatikoa
+ Automatikoa iluntzean
Nabigatzailea
- Chromeko fitxak erabili
- Tut egiteko botoia ezkutatu jaisterakoan.
- Denbora-lerro filtroak
+ Chromeko fitxa pertsonalizatuak erabili
+ Ezkutatu idazteko botoia mugitzean
+ Denbora-lerroko iragazkiak
Fitxak
Erakutsi bultzadak
Erakutsi erantzunak
- Multimedia aurreikusi
- Proxy-a
- HTTP Proxy-a
- HTTP Proxy-a gaitu
- HTTP Proxy-aren zerbitzaria
- HTTP Proxy-aren portua
- Aurrezarritako ikusgarritasuna
- Beti markatu multimedia eduki mingarri gisa
- Bidalketak
+ Jaitsi mediaren aurreikuspenak
+ Proxya
+ HTTP proxya
+ HTTP proxya gaitu
+ HTTP proxyaren zerbitzaria
+ HTTP proxyaren portua
+ Argitarapenen aurrezarritako pribatutasuna
+ Media eduki-mingarri gisa beti markatu
+ Argitaratzeak (zerbitzariarekin sinkronizatua)
Aukerak sinkronizatzean akatsa
Publikoa
- Ezkutukoa
- Pribatua
- Testuaren tamaina
- Oso txikia
+ Zerrendatu gabea
+ Jarraitzaileak soilik
+ Status testuaren tamaina
+ Txikiena
Txikia
Erdikoa
Handia
- Oso handia
+ Handiena
Aipamen berriak
Aipamen berrien jakinarazpenak
- Jarritzaile berriak
+ Jarraitzaile berriak
Jarraitzaile berrien jakinarazpenak
Bultzadak
- Bultzatutako tuten jakinarazpenak
+ Bultzatutako zure tuten jakinarazpenak
Gogokoak
- Gogokoen jakinarazpenak
- %s-k aipatu zaitu
+ Zure tutak gogoko bezala ezartzerakoan jakinarazpenak
+ %s-(e)k aipatu zaitu
%1$s, %2$s, %3$s eta beste %4$d
%1$s, %2$s eta %3$s
%1$s eta %2$s
@@ -205,12 +205,11 @@
Proiektuaren gunea:\n
https://accelf.net/yuito
- Akats jakinarazpenak eta hobekuntza eskariak:\n
- https://github.com/accelforce/Yuito/issues
-
- Yuito-ren profila
- Partekatu edukia
- Partekatu lotura
+ Akatsen berri-emateak eta hobekuntza-eskariak:
+\n https://github.com/accelforce/Yuito/issues
+ Yuitoren profila
+ Partekatu tutaren edukia
+ Partekatu tutaren lotura
Irudiak
Bideoak
Eskaera bidalita
@@ -277,4 +276,196 @@
Ondorengo edukiak erabiltzailearen informazioa erdizka erakutsi dezake. Profil osoa ikusteko nabigatzailean sakatu.
Desainguratu
Ainguratu
+Sareko errore bat sortu da! Zure konexioa ziurta ezazu berriro, mesedez!
+ Mezu Zuzenak
+ Kategoriak
+ Lotuta
+ Ezkutuko domeinuak
+ Programatutako tutak
+ \@%s
+ Kilkerrak besterik ez hemen.
+ Bultzada kendu
+ Gogokoa kendu
+ Editatu
+ Ezabatu eta zirriborroa berriro egin
+ Ezkutuko domeinuak
+ Galdeketa gehitu
+ %s isilarazi
+ Programatutako tutak
+ Tuta programatu
+ Berrezarri
+ Kategoria gehitu
+ Estekak
+ Aipamenak
+ Bultzadak erakutsi
+ Gogokoak erakutsi
+
+ Aipamenak
+ Estekak
+ Ireki media #%d
+
+ %s bezala ireki
+ ... bezala partekatu
+ Media jaisten
+ Media jaisten
+
+ %s ez dago ezkutatua
+
+ Sakatu hemen programatutako tuta konfiguratzeko.
+ Tut hau ezabatu eta zirriborro berria egin\?
+ Ziur al zaude %s ezabatu nahi duzula\? Domeinu horretatik datorren edukia ez duzu denbora-lerro publikoetan edo jakinarazpenentan ikusiko. Domeinu horretan dituzun jarraitzaileak ezabatuko dira.
+ Domeinu osoa ezkutatu
+
+ Galdeketak bukatu dira
+ Iragazkiak
+
+ Erabili sistemaren diseinua
+
+ Hizkuntza
+ Botentzako erakuslea erakutsi
+ GIF abatarrak animatu
+
+ Galdeketak
+ Bukatutako galdeketen jakinarazpenak
+
+
+ Tusky %s
+ Traolak
+ Traolak
+ Tusky-k sustatuta
+ %dh
+ %dm
+ %ds
+
+ Beti zabaldu edukien abisuekin markatutako tootak
+ Elkarrizketak
+ Gehitu iragazkia
+ Editatu iragazkia
+ Kendu
+ Eguneratu
+ Hitz osoa
+ Gako-hitza edo esaldia alfanumerikoa denean bakarrik, hitz osoarekin bat datorrenean bakarrik aplikatuko da
+ Iragazteko esaldia
+
+ Ezin izan da zerrenda sortu
+ Ezin izan da zerrendaren izena aldatu
+ Ezin izan da zerrenda ezabatu
+ Zerrenda sortu
+ Zerrenda berrizendatu
+ Ezabatu zerrenda
+ Editatu zerrenda
+ Bilatu jarraitzen dituzun pertsonak
+ Gehitu kontua zerrendan
+ Kendu kontua zerrendatik
+
+ Google-ren egungo emoji multzoa
+
+ CC-BY 4.0
+ CC-BY-SA 4.0
+
+
+ - %1$s Gogoko
+ - %1$s Gogoko
+
+
+
+ - %s Bultzada
+ - %s Bultzada
+
+
+ Bultzatuta
+ Gogokoa
+
+ %1$s
+ %1$s eta %2$s
+ %1$s, %2$s eta %3$d gehiago
+ geienezko %1$d fitxa iritsita
+
+
+ Media: %s
+ Edukiaren abisua: %s
+ Deskribapenik ez
+ Birblogeatuta
+ Gogotuta
+ Publiko
+ Zerrendagabetuta
+ Jarraitzaileak
+ Zuzena
+ Inkestatu aukerekin: %1$s, %2$s, %3$s, %4$s; %5$s
+
+ Zerrendaren izena
+
+ Editatu traola
+ Traola # gabe
+ Traola
+ Garbitu
+ Iragazi
+ Aplikatu
+
+ Idatzi Toot-a
+ Idatzi
+
+ Ziur zaude jakinarazpen guztiak betirako garbitu nahi dituzula\?
+ %s irudiarentzako ekintzak
+
+ %1$s • %2$s
+
+ - Boto %s
+ - %s Boto
+
+ %s amaitzen da
+ itxita
+
+ Botatu
+
+ Botoa eman duzun galdeketa amaitu da
+ Sortu duzun galdeketa amaitu da
+
+
+ - Egun %d
+ - %d egun
+
+
+ - Ordu %d
+ - %d ordu
+
+
+ - Minutu %d
+ - %d minutu
+
+
+ - Segundu %d
+ - %d segundu
+
+
+ Jarraitu
+ Itzuli
+ Eginda
+ \@%s jakinarazi duzu arrakastaz
+ Iruzkin gehigarriak
+ %s-(r)i birbidali
+ Txostena huts egin du
+ Egoeren eskuratzea huts egin du
+ Txostena zure zerbitzariaren moderatzaileari bidaliko zaio. Jarraian, kontu honen zergatia salatzen duzun azalpena eman dezakezu:
+ Kontua beste zerbitzari batekoa da. Bidali txostenaren kopia anonimatua hara ere\?
+ Kontuak
+ Bilaketa huts egin du
+
+ Erakutsi jakinarazpenen iragazkia
+
+
+ Inkesta
+ 5 minutu
+ 30 minutu
+ Ordu 1
+ 6 ordu
+ Egun 1
+ 3 egun
+ 7 egun
+ Gehitu aukera
+ Aukera anitzak
+ %d. aukera
+ Editatu
+ Errorea agertu da %s mezua bilatzean
+
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index a611d3ab0..fd18d7566 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -19,260 +19,257 @@
بارگذاری ناموفق بود.
خطا در ارسال بوق.
خانه
- اعلانها
+ آگاهیها
محلی
- فدرال
+ همگانی
بوق
- پستها
+ فرستهها
با پاسخ
- دنبالشوندهها
- دنبالکنندهها
+ پی میگیرد
+ پیرو
پسندها
- کاربرهای بیصدا
- کاربرهای مسدود شده
- درخواستهای دنبال کردن
- ویرایش نمایه شما
+ کاربران خموش
+ کاربران مسدود
+ درخواستهای پیگیری
+ ویرایش نمایهتان
پیشنویسها
- مجوزها
+ پروانهها
%s تقویت شد
- محتوی حساس
- پنهان کردن رسانه
- برای نمایش کلیک کن
- نمایش بیشتر
- نمایش کمتر
- گسترش دادن
- بستن
- چیزی اینجا نیست. برای تازهسازی، به پایین بکشید!
- %s بوق شما را تقویت کرد
- %s بوق شما را پسندید
- %s شما را دنبال میکند
+ محتوای حسّاس
+ رسانهٔ پنهان
+ کلیک برای نمایش
+ نمایش بیشتر
+ نمایش کمتر
+ گسترش
+ جمع
+ چیزی اینجا نیست. برای تازهسازی، به پایین بکشید!
+ %s بوقتان را تقویت کرد
+ %s بوقتان را پسندید
+ %s پیگیرتان شد
گزارش @%s
- پیامهای اضافی؟
+ توضیحات اضافی؟
پاسخ سریع
پاسخ
تقویت
پسند
- بیشتر
+ بیشتر
ایجاد
- با ماستودون وارد شو
+ ورود با ماستدون
خروج
- آیا از خارج شدن از این حساب %1s اطمینان دارید؟
- دنبال کن
- لغو دنبال کردن
- مسدودسازی
+ مطمئنید میخواهید از حساب %1s خارج شوید؟
+ پیگیری
+ ناپیگیری
+ انسداد
رفع انسداد
- تقویت را پنهان کن
+ نهفتن تقویتها
نمایش تقویتها
گزارش
حذف
بوق
بوق!
- تلاش مجدد
- بببند
+ تلاش دوباره
+ بستن
نمایه
ترجیحات
ترجیحات حساب
پسندها
- کاربران بیصدا
- کاربران مسدود شده
- درخواستهای دنبال کردن
+ کاربران خموش
+ کاربران مسدود
+ درخواستهای پیگیری
رسانه
- باز کردن در مرورگر
+ گشودن در مرورگر
افزودن رسانه
- عکس بگیر
- اشتراک
- بیصدا
- لغو بیصدا
+ گرفتن عکس
+ همرسانی
+ خموش
+ گویا
اشاره
- رسانه پنهان شود
- کشو را باز کن
+ نهفتن رسانه
+ گشودن کشو
ذخیره
ویرایش نمایه
ویرایش
بازگرداندن
پذیرش
رد
- جستجو
- پیشنویس
- نمایش بوق
+ جستوجو
+ پیشنویسها
+ نمایانی بوق
هشدار محتوا
- صفحه کلیک شکلک
- درحال دریافت %1$s
- رونوشت پیوند
+ صفحهکلید اموجی
+ در حال بارگیری %1$s
+ رونوشت از پیوند
همرسانی نشانی بوق با…
همرسانی بوق با…
همرسانی رسانه با…
فرستاده شد!
کاربر رفع انسداد شد
- کاربر رفع بیصدا شد
+ کاربر گویا شد
فرستاده شد!
- پاسخ با موفق فرستاده شد.
+ پاسخ با موفقیت فرستاده شد.
کدام نمونه؟
چه خبر؟
هشدار محتوا
نام نمایشی
- بیوگرافی
- جستجو…
- نتیجهای نیست
+ شرح حال
+ جستوجو…
+ بدون هیچ نتیجه
پاسخ …
آواتار
سرایند
- یک نمونه چیست؟
+ نمونه چیست؟
در حال اتصال …
- آدرس یا دامنه هر نمونه را میتوانید وارد کنید، مثلا mastodon.social، icosahedron.website، social.tchncs.de، و بیشتر!
+ اینجا میتواند نشانی یا دامنهٔ هر نمونه را وارد کنید، مثلا mastodon.social، icosahedron.website، social.tchncs.de، و بیشتر!
\n
-\n اگر شما هنوز حساب کاربری ندارید، میتوانید نام نمونه مورد نظر را وارد کنید از اینجا بپیوندید و حساب کاربری ایجاد کنید.
+\n اگر هنوز حساب کاربری ندارید، میتوانید نام نمونهٔ مورد نظر برای پیوستن را وارد کرده و حساب کاربری بسازید.
\n
-\n نمونه جایی است که حساب کاربری شما میزبان آن است اما شما به راحتی میتوانید با افراد دیگر در نمونههای دیگر ارتباط برقرار کنید و آنها را دنبال کنید شما درست مثل اینکه در یکجا باشید.
+\n نمونه جایی است که حسابتان میزبانی میشود، ولی به راحتی میتوانید با افراد دیگر در نمونههای دیگر ارتباط برقرار کرده و آنان را دنبال کنید، درست مثل این که در یک جا باشید.
\n
-\n برای اطلاعات بیشتر به اینجا مراجعه کنید joinmastodon.org.
+\n برای اطّلاعات بیشتر به اینجا مراجعه کنید joinmastodon.org.
پایان بارگذاری رسانه
در حال بارگذاری…
بارگیری
- درخواست دنبال کردن را لغو میکنید؟
- لغو دنبال کردن این حساب؟
+ لغو درخواست پیگیری؟
+ لغو پیگیری این حساب؟
حذف این بوق؟
- عمومی:پست به خط زمانی عمومی
- خارج از لیست: در خط زمانی عمومی نشان نده
- تنها دنبالکنندگان:پست فقط به دنبالکنندگان
- مستقیم:پست فقط برای کاربران صدا زده شده
- ویرایش اعلانها
- اعلانها
+ عمومی: فرستادن به خط زمانیهای عمومی
+ فهرستنشده: نشان ندادن در خط زمانیهای عمومی
+ فقط پیروان: فرستادن فقط به پیروان
+ مستقیم: فرستادن فقط برای کاربران مورد اشاره
+ آگاهیها
+ آگاهیها
هشدارها
- اعلان با صدا
- اعلان با لرزش
- اعلان با نور
- به من اطلاع بده زمانی که
- صدازدهها
- دنبالشده
- پستهای تقویت شده من
- پستهای پسندیده شدهٔ من
+ آگاهی با صدا
+ آگاهی با لرزش
+ آگاهی با چراغ
+ مرا آگاه کن هنگام
+ اشاره شدن
+ دنبال شدن
+ تقویت بوقهایم
+ پسند بوقهایم
ظاهر
- تم برنامه
- خطهای زمانی
+ زمینهٔ کاره
+ خط زمانیها
تاریک
روشن
سیاه
- خودکار برحسب غروب خورشید
+ خودکار در غروب
مرورگر
استفاده از زبانههای سفارشی کروم
- پنهان کردن دکمه ایجاد هنگام پیمایش
- فیلتر کردن خط زمانی
+ نهفتن دکمهٔ ایجاد، هنگام پیمایش
+ پالایش خط زمانی
زبانهها
نمایش تقویتها
نمایش پاسخها
- پیشنمایش رسانه را نشان بده
- پراکسی
- پراکسی HTTP
- فعالسازی پراکسی HTTP
- سرور پراکسی HTTP
- درگاه پراکسی HTTP
- حریم خصوصی پیشفرض پست
- همواره رسانه را به عنوان حساس نشانهگذاری کن
- انتشار (همگادم با کارساز)
- ناتوانی در همگامسازی تنظیمات
+ بارگیری پیشنمایش رسانهها
+ پیشکار
+ پیشکار HTTP
+ به کار انداختن پیشکار HTTP
+ کارساز پیشکار HTTP
+ درگاه پیشکار HTTP
+ محرمانگی پیشگزیدهٔ فرسته
+ علامتگذاری همیشگی رسانه به عنوان حساس
+ انتشار (همگام با کارساز)
+ شکست در همگامسازی تنظیمات
عمومی
- فهرست نشده
- فقط دنبالکنندگان
- اندازه متن وضعیت
+ فهرستنشده
+ فقط پیروان
+ اندازهٔ متن وضعیت
بسیار کوچک
کوچک
متوسط
بزرگ
بسیار بزرگ
اشارههای جدید
- اعلان در مورد اشارههای جدید
- دنبالکنندههای جدید
- اعلان درمورد دنبالکنندگان جدید
+ آگاهیها در مورد اشارههای جدید
+ پیروان جدید
+ آگاهیها درمورد پیروان جدید
تقویتها
- وقتی بوقهای شما تقویت شد اعلان بده
+ آگاهیها هنگام تقویت بوقهایتان
پسندها
- اعلانها وقتی که بوقهای شما پسندیده شوند
- %s شما را صدا زد
- %1$s, %2$s, %3$s و %4$d دیگر
+ آگاهیها هنگام پسندیده شدن بوقهایتان
+ %s به شما اشاره کرد
+ %1$s, %2$s, %3$s و %4$d نفر دیگر
%1$s, %2$s, و %3$s
%1$s و %2$s
- %d تعاملات جدید
- حساب قفل شد
+ %d برهمکنش جدید
+ حساب قفلشده
درباره
- Yuito یک برنامه آزاد و متنباز است که تحت مجوز GNU General Public License Version 3. منتشر شده است.\n
- شما میتوانید مجوز را از اینجا ببینید:\n
- https://www.gnu.org/licenses/gpl-3.0.en.html
+ ییتو نرمافزاری آزاد است که تحت نگارش ۳ از پروانهٔ جامع همگانی گنو منتشر شده است. پروانه را میتوانید از اینجا ببینید:
+\n https://www.gnu.org/licenses/gpl-3.0.en.html
- سایت پروژه\n
- https://accelf.net/yuito
-
- گزارش خطا و درخواست ویژگی:\n
- https://github.com/accelforce/Yuito/issues
-
- نمایه Yuito
- همرسانی محتوی بوق
- همرسانی لینک بوق
+ پایگاه وب پروژه:
+\n https://tusky.app
+ گزارش مشکلات و درخواست ویژگیها:
+\n https://github.com/accelforce/Yuito/issues
+ نمایهٔ ییتو
+ همرسانی محتوای بوق
+ همرسانی پیوند بوق
تصویرها
فیلم
- درخواست دنبالکردن فرستاده شد
- بدون محتوی
+ تقاضای پیگیری شد
+ بدون هیچ محتوا
در %dسال
در %dر
در % dس
در %dد
در %dث
- شما را دنبال میکند
- همیشه مطلب حساس را نشان بده
+ پیگیرتان است
+ نمایش همیشگی محتوای حساس
رسانه
- پاسخ دادن به @%s
- بارگیری بیشتر
+ در حال پاسخ به @%s
+ بارگیری بیشتر
افزودن حساب
افزودن حساب ماستدون جدید
- سیاههها
- سیاههها
- لیست خط زمانی
- پست با حساب %1$s
- ناتوان در تنظیم عنوان
+ فهرستها
+ فهرستها
+ خط زمانی فهرست
+ در حال فرستادن با حساب %1$s
+ شکست در تنظیم عنوان
توصیف برای کمبینایان\n(محدودیت نویسه %d)
تنظیم عنوان
- حذف
+ برداشتن
قفل حساب
- به شما امکان میدهد بصورت دستی دنبالکنندگان را تایید کنید
- ذخیره به عنوان پیشنویس؟
- فرستادن بوق…
+ میگذارد پیروانتان را به صورت دستی تأیید کنید
+ ذخیرهٔ پیشنویس؟
+ در حال فرستادن بوق…
خطای فرستادن بوق
در حال فرستادن بوقها
فرستادن لغو شد
- یک رونوشت از بوق در پیشنویسها ذخیره شد
+ رونوشتی از بوق در پیشنویسهایتان ذخیره شد
ایجاد
- سرور شما %s هیچ شکلک سفارشی ندارد
- به کلیپ بورد کپی شد
- قالب شکلک
- پیشفرض سیستم
- شما ابتدا باید این شکلکها را دریافت کنید
- اجرای جستجو…
- گستردن/بستن همه وضعیتها
- بوق را باز کن
- برنامه به شروع مجدد نیاز دارد
- شما برای اعمال این تغییرات به شروع مجدد برنامه نیاز دارید
- بعدا
- شروع مجدد
- شکلکهای پیشفرض دستگاه شما تنظیم شدند
- شکلکها از اندروید 4.4–7.1 شناخته شدهاند
- شکلکهای استاندارد ماستدون تنظیم شدند
- بارگیری با شکست مواجه شد
+ نمونهتان %s هیچ اموجی سفارشیای ندارد
+ در تختهگیره رونوشت شد
+ سبک اموجی
+ پیشگزیدهٔ سامانه
+ نخست باید این اموجیها را بارگیری کنید
+ اجرای جستوجو…
+ گسترده/جمع کردن تمام وضعیتها
+ گشودن بوق
+ نیاز به شروع دوبارهٔ کاره
+ برای اعمال این تغییرات، نیاز به شروع دوبارهٔ تاسکی دارید
+ بعداً
+ شروع دوباره
+ مجموعهٔ اموجی پیشگزیدهٔ افزارهتان
+ اموجیهای اندروید ۴.۴ تا ۷.۱
+ مجموعهٔ اموجی استاندارد ماستدون
+ شکست در بارگیری
بات
- %1$s جابجا شد به:
+ %1$s منتقل شد به:
تقویت برای مخاطب اصلی
لغو تقویت
- Yuito شامل کد و داراییهای پروژههای منبعباز زیر است:
- تحت مجوز آپاچی (رونوشت در ادامه)
- متاداده نمایه
+ ییتو شامل کد و داراییهایی از پروژههای آزاد زیر است:
+ تحت پروانهٔ آپاچی (رونوشت در ادامه)
+ فرادادهٔ نمایه
افزودن داده
برچسب
- محتوی
+ محتوا
استفاده از زمان مطلق
اطلاعات زیر ممکن است به طور ناقص نمایه کاربر را نشان دهد. برای دیدن نمایه کامل در مرورگر، لمس کنید.
برداشتن سنجاق
@@ -280,83 +277,82 @@
یک خطای شبکه رخ داد! لطفا اتصال خود را بررسی و دوباره تلاش کنید!
پیامهای مستقیم
زبانهها
- #%ث
- سنجاقشدهها
+ سنجاقشده
دامنههای پنهان
\@%s
- چیزی اینجا نیست.
- حذف بازبوق
- حذف پسند
- پاک کردن و بازنویسی
+ چیزی اینجا نیست.
+ برداشتن تقویت
+ برداشتن پسند
+ حذف و بازنویسی
دامنههای پنهان
افزودن نظرسنجی
- بیصدا کردن %s
- افزوده زبانه
+ خموشی %s
+ افزودن زبانه
پیوندها
اشارهها
- هشتگها
- بازکردن حساب بازبوق کننده
- نمایش بازبوقها
- نمایش پسندیدهها
+ برچسبها
+ گشودن تقویتگر
+ نمایش تقویتها
+ نمایش پسندها
- هشتگها
+ برچسبها
اشارهها
پیوندها
- بازکردن رسانه #%d
+ گشودن رسانهٔ #%d
- باز کردن به عنوان %s
+ گشودن به عنوان %s
همرسانی به عنوان …
بارگیری رسانه
در حال بارگیری رسانه
%s ناپنهان
- میخواهید این بوق را پاک و بازنویسی کنید؟
- پنهان کردن تمام دامنه
+ حذف و بازنویسی این بوق؟
+ نهفتن تمام دامنه
- نظرسنجیهای پایان یافته
- صافیها
+ پایان نظرسنجیها
+ پالایهها
- استفاده از طرح سیستم
+ استفاده از طراحی سامانه
زبان
- نمایش نشان برای باتها
- پویانمایی آواتار gif
+ نمایش نشانگر برای باتها
+ پویانمایی آواتارهای جیف
نظرسنجیها
- اعلانها درباره نظرسنجیهایی که پایان یافتهاند
+ آگاهیها در مورد نظرسنجیهای پایانیافته
- Tusky (تاسکی) %s
+ تاسکی %s
%dسال
%dر
%dس
%dد
%dث
- همواره بوقهایی که دارای محتوای حساس هستند را گسترش بده
- خط زمانی عمومی
- گفتگوها
- افزودن صافی
- ویرایش صافی
- پاک کردن
- بهروزرسانی
- تمام کلمه
- ناتوانی در ایجاد سیاهه
- ناتوانی در تغییر نام سیاهه
- ناتوانی در حذف سیاهه
- ایجاد یک سیاهه
- تغییر نام سیاهه
- حذف سیاهه
- ویرایش سیاهه
- جستجو بین افرادی که دنبال میکنید
- افزودن حساب به سیاهه
- حذف حساب از سیاهه
+ گسترش همیشگی بوقهای علامت خورده با هشدار محتوا
+ خط زمانیهای عمومی
+ گفتوگوها
+ افزودن پالایه
+ ویرایش پالایه
+ برداشتن
+ بهروز رسانی
+ تمام واژه
+ ناتوانی در ایجاد فهرست
+ ناتوانی در تغییر نام فهرست
+ ناتوانی در حذف فهرست
+ ایجاد یک فهرست
+ تغییر نام فهرست
+ حذف فهرست
+ ویرایش فهرست
+ جستوجو برای دنبالشوندگانتان
+ افزودن حساب به فهرست
+ حذف حساب از فهرست
- مجموعه شکلکهای جاری گوگل
+ مجموعهٔ اموجی کنونی گوگل
- CC-BY 4.0
- CC-BY-SA 4.0
+ نگارش ۴ CC-BY
+ نگارش ۴ CC-BY-SA
- %1$s پسند
@@ -364,56 +360,56 @@
- - %s بازبوق
- - %s بازبوق
+ - %s تقویت
+ - %s تقویت
- بازبوق شده توسط
- پسنندهشده توسط
+ تقویت به دست
+ پسندیده به دست
%1$s
%1$s و %2$s
- %1$s، %2$s و %3$d بیشتر
- به بیشینه %1$d زبانه رسید
+ %1$s، %2$s و %3$d نفر دیگر
+ رسیده به بیشینهٔ %1$d زبانه
رسانه: %s
هشدار محتوا: %s
- بدون توضیحات
+ بدون هیج توضیحی
بازبوقیده
پسندیده
عمومی
فهرستنشده
- دنبالکنندگان
+ پیروان
مستقیم
نظرسنجی با انتخابها: %1$s، %2$s، %3$s، %4$s؛ %5$s
- نام سیاهه
+ نام فهرست
- ویرایش هشتگ
- هشتگ بدون #
- هشتگ
- پاک کردن
- صافی
+ ویرایش برچسب
+ برچسب بدون #
+ برچسب
+ پاکسازی
+ پالایش
اعمال
ایجاد بوق
ایجاد
- مطمئنید که به طور دائمی میخواهید اعلانها را پاک کنید؟
- کنشها برای تصاویر %s
+ مطمئنید میخواهید تمام آگاهیهایتان را برای همیشه پاک کنید؟
+ کنشها برای تصویر %s
- - %s رای
- - %s رای
+ - %s رأی
+ - %s رأی
- %s باقی مانده
- پایان یافته در %s
- بسته شده
- رای
+ %s مانده
+ پایان در %s
+ بسته
+ رأی
- یک نظرسنجی که در آن رای دادهاید پایان یافته است
- یک نظرسنجی ساختهاید پایان یافته است
+ یک نظرسنجی که در آن رأی دادید، تمام شد
+ یک نظرسنجی که ساختید، تمام شد
- %d روز
@@ -433,17 +429,17 @@
ادامه
- قبل
- اتمام
- با موفقیت گزارش شد @%s
- نظرات بیشتر
+ بازگشت
+ تمام
+ \@%s با موفّقیت گزارش شد
+ نظرات اضافی
هدایت به %s
- ناتوانی در گزارش
- ناتوانی در دریافت وضعیتها
+ شکست در گزارش
+ شکست در واکشی وضعیتها
حسابها
- ناتوانی در جستجو
+ شکست در جستوجو
- نمایش فیلتر اعلانات
+ نمایش پالایهٔ آگاهیها
نظرسنجی
@@ -455,8 +451,24 @@
۳ روز
۷ روز
افزودن گزینه
- گزینههای چندگانه
- گزینه %d
+ چندگزینهای
+ گزینهٔ %d
ویرایش
-
+بوقهای زمانبندیشده
+ ویرایش
+ بوقهای زمانبندیشده
+ زمانبندی بوق
+ بازنشانی
+ برای پیکربندی بوق زمانبندیشده، اینجا را بزنید.
+ مطمئنید میخواهید تمام %s را مسدود کنید؟ محتوای آن دامنه را در هیچیک از خط زمانیها یا در آگاهیهایتان نخواهید دید. پیروانتان از آن دامنه، برداشته خواهند شد.
+ هنگامی که کلیدواژه یا عبارت، فقط حروفعددی باشد، فقط اگر با تمام واژه مطابق باشد، اعمال خواهد شد
+ عبارت پالایش
+
+ %1$s • %2$s
+ گزارش به ناظمهای کارسازتان ارسال خواهد شد. میتوانید توضیحی در باب چرایی گزارش این حساب در زیر بنویسید:
+ این حساب از کارسازی دیگر است. رونوشتی ناشناس از گزارش، به آنجا نیز ارسال شود؟
+ خطا در یافتن فرستهٔ %s
+
+قدرتگرفته از تاسکی
+
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index c6f58c334..bb5175517 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -26,7 +26,6 @@
Messages directs
Onglets
Pouet
- #%s
Pouets
Pouets & réponses
Épinglés
@@ -364,17 +363,17 @@
Direct
Nom de la liste
-Modifier les hashtags
- Hastags sans #
+Édition des hashtags
+ Hashtags sans #
Hashtag
-Nettoyer
+Effacer
Filtrer
Appliquer
- Ecrire un pouet
- Ecrire
+ Écrire un pouet
+ Écrire
Afficher l\'indicateur de robots
Nettoyer toutes les notifications de façon permanente \?
@@ -393,7 +392,7 @@
Sondages
- Les sondages sont clos
+ Les sondages sont terminés
Notifications pour les sondages terminés
@@ -421,7 +420,6 @@
Actions pour l’image %s
%1$s • %2$s
- <b>%1$d%%</b> %2$s
Un sondage auquel vous avez participé vient de se terminer
@@ -469,4 +467,13 @@
Choix %d
Éditer
-
+Pouets planifiés
+ Éditer
+ Pouets planifiés
+ Planifier le pouet
+ Réinitialiser
+ Appuyez ici pour configurer le pouet planifié.
+ Erreur lors de la recherche du post %s
+
+Propulsé par Tusky
+
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
new file mode 100644
index 000000000..54d04dc9a
--- /dev/null
+++ b/app/src/main/res/values-hi/strings.xml
@@ -0,0 +1,29 @@
+
+मॅस्टोडौन के साथ लॉगिन करें
+ पसंदीदा
+ ड्राफ्ट
+ लॉग आउट
+ पसंद
+ खाता प्राथमिकताएं
+ प्रोफाइल एडिट करें
+ खोज
+ के बारे में
+ उत्तरों के साथ
+ फॉलोअर्स
+ उत्तर दें
+ फॉलो
+ अनफॉलो
+ ब्लॉक
+ अनब्लॉक
+ बूस्ट छिपाएं
+ बूस्ट दिखाएं
+ रिपोर्ट करें
+ एडिट करें
+ डिलीट करें
+ डिलीट एवं रिड्राफ्ट करें
+ टूट करें
+ टूट!
+ पुनः प्रयास करें
+ बंद करें
+ प्रोफाइल
+
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 5eaa41764..9b85ab5df 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -26,7 +26,6 @@
Közvetlen üzenetek
Fülek
Tülk
- #%s
Tülkölés
Válaszokkal
Rögzített
@@ -413,7 +412,6 @@
%s maradt
vége %s
véget ért
- <b>%1$d%%</b> %2$s
Szavazás
@@ -467,4 +465,12 @@
Válasz %d
Szerkesztés
+Időzített tülkök
+ Szerkesztés
+ Időzített tülkök
+ Tülk Időzítése
+ Visszaállítás
+ Ide nyúlj az időzített tülkök beállításához.
+ Nem találjuk ezt a posztot %s
+
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 20d01ae59..f2f8f77ce 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -26,7 +26,6 @@
Messaggi Diretti
Schede
Toot
- #%s
Post
Con risposte
Fissati in alto
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index a4848994a..cdbfb3a49 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -25,7 +25,6 @@
ダイレクトメッセージ
タブ
スレッド
- #%s
投稿
投稿と返信
ピン留め
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 05caa435b..3b0ce27cc 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -28,7 +28,6 @@
다이렉트 메시지
탭
툿
- #%s
게시물
툿과 답장
고정됨
@@ -450,7 +449,6 @@
%s 남음
%s에 종료
마감됨
- %1$d%% %2$s
투표
diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml
new file mode 100644
index 000000000..115777223
--- /dev/null
+++ b/app/src/main/res/values-ml/strings.xml
@@ -0,0 +1,62 @@
+
+മസ്റ്റഡോൺ വഴി പ്രവേശിക്കുക
+ എന്താണ് ഒരു ഇൻസ്റ്റൻസ്\?
+
+ പ്രിയപ്പെട്ടവ
+ കരടുകൾ
+ പുറത്തിറങ്ങുക
+ മുൻഗണനകൾ
+ അക്കൗണ്ട് മുൻഗണനകൾ
+ പ്രൊഫൈൽ തിരുത്തുക
+ തിരയുക
+ വിവരം
+ പട്ടികകൾ
+ പട്ടികകൾ
+ ഒരു പിഴവ് സംഭവിച്ചിരിക്കുന്നു.
+ ഒരു നെറ്റ്വർക്ക് പിഴവ് സംഭവിച്ചിരിക്കുന്നു! ദയവായി താങ്കളുടെ കണക്ഷൻ പരിശോധിച്ചിട്ട് വീണ്ടും ശ്രമിക്കൂ!
+ ഇത് ശൂന്യമാവാൻ പാടില്ല.
+ അസാധുവായ ഡൊമൈൻ നൽകിയിരിക്കുന്നു
+ ആ ഇൻസ്റ്റൻസുമായി ആധികാരികത ഉറപ്പുവരുത്തുന്നതിൽ പരാജയപ്പെട്ടിരിക്കുന്നു.
+ ഉപയോഗിക്കാനായി ഒരു വെബ് ബ്രൗസർ കണ്ടെത്താനായില്ല.
+ അജ്ഞാതമായ ഒരു ആധികാരികതാപിഴവ് സംഭവിച്ചിരിക്കുന്നു.
+ ആധികാരികത ഉറപ്പുവരുത്താനായില്ല.
+ ഒരു പ്രവേശന ടോക്കൺ ലഭ്യമാക്കുന്നതിൽ പരാജയപ്പെട്ടു.
+ ഈ സ്റ്റാറ്റസ് വളരെ നീളമേറിയതാണ്!
+ ഫയൽ 8 എംബിയേക്കാളും ചെറുതായിരിക്കണം.
+ ചലച്ചിത്ര ഫയലുകൾ 40 എംബിയേക്കാളും ചെറുതായിരിക്കണം.
+ ഇത്തരം ഫയൽ അപ്ലോഡ് ചെയ്യാൻ സാധിക്കില്ല.
+ ഈ ഫയൽ തുറക്കാനായില്ല.
+ മീഡിയ വായിക്കുവാനുള്ള അനുമതി ആവശ്യമാണ്.
+ മീഡിയ സംഭരിക്കുവാനുള്ള അനുമതി ആവശ്യമാണ്.
+ ചിത്രങ്ങളും ചലച്ചിത്രങ്ങളും ഒരുമിച്ച് ഒരു സ്റ്റാറ്റസിലേക്ക് ചേർക്കാനാവില്ല.
+ അപ്ലോഡ് പരാജയപ്പെട്ടു.
+ ടൂട്ട് അയയ്ക്കുന്നതിൽ പിഴവ്.
+
+ പൂമുഖം
+ അറിയിപ്പുകൾ
+ ലോക്കൽ
+ ഫെഡറേറ്റഡ്
+ നേരേയുള്ള സന്ദേശങ്ങൾ
+ ടാബുകൾ
+ ടൂട്ട്
+ പോസ്റ്റുകൾ
+ മറുപടികളോടൊപ്പം
+ പിൻ ചെയ്തത്
+ പിന്തുടരലുകൾ
+ പിന്തുടരുന്നവർ
+ നിശ്ശബ്ദരാക്കിയ ഉപയോക്താക്കൾ
+ തടയപ്പെട്ട ഉപയോക്താക്കൾ
+ പിന്തുടരാനുള്ള അപേക്ഷകൾ
+ പ്രൊഫൈൽ തിരുത്തുക
+ മറുപടി
+ ബൂസ്റ്റ്
+ ബൂസ്റ്റ് പിൻവലിക്കുക
+ ഇഷ്ടപ്പെട്ടവ
+ ഇഷ്ടപ്പെട്ടവയിൽ നിന്നും കളയുക
+ കൂടുതൽ
+ പിന്തുടരുക
+ പിന്തുടരുന്നത് അവസാനിപ്പിക്കുക
+ വീണ്ടും ശ്രമിക്കുക
+ പിന്തുടരുവാനുള്ള അഭ്യര്ത്ഥനകള്
+ മറയ്ക്കപ്പെട്ട ഡൊമൈനുകൾ
+
diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml
index 372329bb1..6ab982f7b 100644
--- a/app/src/main/res/values-night/styles.xml
+++ b/app/src/main/res/values-night/styles.xml
@@ -27,10 +27,9 @@
- @color/window_background_dark
- @color/custom_tab_toolbar_dark
- - @color/toolbar_background_dark
- - @color/toolbar_icon_dark
+ - @color/toolbar_icon_dark
- @style/TuskyImageButton.Dark
- - @drawable/ic_reblog_dark_18dp
+ - @drawable/ic_reblog_dark_24dp
- @drawable/reblog_inactive_dark
- @drawable/reblog_private_dark
- @drawable/reblog_unleakable_dark
@@ -45,7 +44,7 @@
- @drawable/status_divider_dark
- @drawable/conversation_thread_line_dark
- @color/tusky_blue
- - @drawable/tab_page_margin_dark
+ - @color/tab_page_margin_dark
- @color/color_background_dark
- @color/toolbar_icon_dark
- @color/account_toolbar_icon_collapsed_dark
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index b3bb35606..262d0184f 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -26,7 +26,6 @@
Directe berichten
Tabs
Toot
- #%s
Toots
Met reacties
Vastgezet
@@ -390,7 +389,6 @@
%s over
eindigt op %s
gesloten
- <b>%1$d%%</b> %2$s
Stemmen
diff --git a/app/src/main/res/values-no-rNB/strings.xml b/app/src/main/res/values-no-rNB/strings.xml
index 06e1e74b1..7f490ffbb 100644
--- a/app/src/main/res/values-no-rNB/strings.xml
+++ b/app/src/main/res/values-no-rNB/strings.xml
@@ -28,7 +28,6 @@
Direktemeldinger
Faner
Toot
- #%s
Toots
Med svar
Festet
@@ -410,7 +409,6 @@
%s igjen
avsluttes %s
stengt
- <b>%1$d%%</b> %2$s
Stem
@@ -504,4 +502,13 @@
Valg %d
Endre
-
+Planlagte toots
+ Rediger
+ Planlagte toots
+ Planlegg toot
+ Tilbakestill
+ Klikk her for å konfigurere planlagt toot.
+ Det oppsto en feil under henting av %s
+
+Drevet av Tusky
+
diff --git a/app/src/main/res/values-oc/strings.xml b/app/src/main/res/values-oc/strings.xml
index ac34cba3b..c03115443 100644
--- a/app/src/main/res/values-oc/strings.xml
+++ b/app/src/main/res/values-oc/strings.xml
@@ -274,7 +274,6 @@
Local
Messatges dirèctes
Onglets
- #%s
Penjats
\@%s
Pas res aicí.
@@ -405,7 +404,6 @@
%1$s • %2$s
- <b>%1$d%%</b> %2$s
Un sondatge ont avètz votat es acabat
Un sondatge qu’avètz creat es acabat
@@ -474,4 +472,13 @@
Opcion %d
Modificar
-
+Tuts planificats
+ Modificar
+ Tuts planificats
+ Planificar de tuts
+ Escafar
+ Tocatz aquí per configurar los tuts planificats.
+ Error en cercant la publicacion %s
+
+Propulsat per Tusky
+
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index baa25bcae..88cde261e 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -288,10 +288,9 @@
Otwórz jako %s
Udostępnij jako …
Zakładki
- #%s
Ukryte domeny
\@%s
- Usuń podbicie
+ Cofnij podbicie
Ukryte domeny
Dodaj głosowanie
Wycisz %s
@@ -424,7 +423,6 @@
Zostało %s
kończy się %s
zakończone
- <b>%1$d%%</b> %2$s
Głosuj
@@ -481,4 +479,13 @@
Opcja %d
Edytuj
+Zaplanowane wpisy
+ Edytuj
+ Zaplanowane wpisy
+ Zaplanuj wpis
+ Resetuj
+ Dotknij tutaj, żeby skonfigurować zaplanowany wpis.
+ Napędzane przez Tusky
+ Błąd przy wyszukiwaniu wpisu %s
+
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 41d13e4f4..0afc04a18 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -294,7 +294,6 @@
Seguidores
Ocorreu um erro de conexão! Por favor, verifique sua internet e tente novamente!
- #%s
Fixado
\@%s
Expandir
@@ -400,7 +399,6 @@
%s restando
termina em %s
Terminou
- <b>%1$d%%</b> %2$s
Votar
@@ -438,7 +436,7 @@
Falha na denúncia
Falha ao carregar toots
A denúncia será enviada para o seu administrador da instância. Você pode explicar por que você denunciou a conta:
- A conta está em outra instância. Enviar uma cópia anonimizada da denúncia também\?
+ A conta está em outra instância. Enviar uma cópia anônima da denúncia também\?
Instâncias bloqueadas
Instâncias bloqueadas
@@ -469,4 +467,12 @@
Opção %d
Editar
+Toots agendados
+ Editar
+ Toots agendados
+ Agendar toot
+ Cancelar
+ Toque aqui para agendar
+ Erro ao pesquisar %s
+
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index b9468d8f4..cefb327cf 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -28,7 +28,6 @@
Личные сообщения
Вкладки
Обсуждение
- #%s
Посты
Посты и ответы
Закреплённые
@@ -405,11 +404,10 @@
Закрепить
- - <b>%1$s</b> Понравилось
- - <b>%1$s</b> Понравилось
- - <b>%1$s</b> Понравилось
- - <b>%1$s</b> Понравилось
-
+ - %1$s Понравилось
+ - %1$s Понравились
+ - %1$s Понравилось
+
- <b>%s</b> Продвинул(а)
@@ -482,9 +480,6 @@
%s
завершится %s
завершён
-
-
- <b>%1$d%%</b> %2$s
Голосовать
@@ -540,4 +535,12 @@
Вариант %d
Изменить
+Отложенные записи
+ Изменить
+ Отложенные записи
+ Отложить запись
+ Сброс
+ Нажмите для выбора времени отправки.
+ Ошибка при поиске сообщения / ний
+
diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml
index e83aaf62a..ba78d6824 100644
--- a/app/src/main/res/values-sl/strings.xml
+++ b/app/src/main/res/values-sl/strings.xml
@@ -27,7 +27,6 @@
Neposredna Sporočila
Zavihki
Tut
- #%s
Objave
Z odgovori
Pripeto
@@ -36,7 +35,7 @@
Priljubljene
Utišani uporabniki
Blokirani uporabniki
- Zahteve za sledenje
+ Prošnje za sledenje
Uredi svoj profil
Osnutki
Licence
@@ -89,7 +88,7 @@
Priljubljeni
Utišani uporabniki
Blokirani uporabniki
- Zahteve za sledenje
+ Prošnje za sledenje
Mediji
Odpri v brskalniku
Dodaj medij
@@ -417,7 +416,6 @@
še %s
se konča ob %s
zaprto
- <b>%1$d%%</b> %2$s
Glasovanje
@@ -518,4 +516,13 @@
Izbira %d
Uredi
-
+Napovedani tuti
+ Uredi
+ Napovedani tuti
+ Ponastavi
+ Napovej tut
+ Dotaknite se tukaj, da nastavite napovedan tut.
+ Napaka pri iskanju objave %s
+
+Poganja ga Tusky
+
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index e64e67a03..828c2e899 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -26,7 +26,6 @@
Direkta meddelanden
Flikar
Toot
- #%s
Inlägg
Med svar
Fastnålade
@@ -388,7 +387,6 @@
%s kvar
avslutas %s
stängd
- <b>%1$d%%</b> %2$s
Rösta
@@ -465,4 +463,12 @@
Val %d
Redigera
+Schemalagda toots
+ Redigera
+ Schemalagda toots
+ Schemalägg toot
+ Återställ
+ Knacka här för att konfigurera schemalagd toot.
+ Fel vid uppslagning av status %s
+
diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml
index 7040478ab..8bf55ac78 100644
--- a/app/src/main/res/values-ta/strings.xml
+++ b/app/src/main/res/values-ta/strings.xml
@@ -1,4 +1,4 @@
-
+
பிழை ஏற்பட்டது.
இது காலியாக இருக்க கூடாது.
@@ -18,14 +18,14 @@
பதிவேற்றம் தோல்வியுற்றது.
முகப்பு
அறிவிப்புகள்
- அருகாமயில்
+ அருகாமையில்
ஒருங்கிணைந்த
பதிவுகள்
பதிலளிக்கபட்டவை
பின்பற்றுகிறீர்
- பின்பற்றுபவர்கள்
- பிடித்தவைகள்
- ஒலி நீக்கபட்ட பயனர்கள்
+ தொடர்பவர்கள்
+ விரும்பியவை
+ ஒதுக்கப்பட்ட பயனர்கள்
தடைசெய்யபட்ட பயனர்கள்
பின்பற்ற கோரிக்கை
சுயவிவரத்தை திருத்த
@@ -259,4 +259,16 @@
கீழுள்ள தகவல் பயனரின் சுயவிவரத்தின் பிரதிபலிப்பு முழுமையடையாது. முழு சுயவிவரத்தை உலாவில் திறக்க அழுத்தவும்.
விடுவி
பொருத்து
-
+கணக்கரின் முன்னுரிமைகள்
+ "பிணைய பிழை ஏற்பட்டது! உங்கள் இணைப்பைச் சரிபார்த்து மீண்டும் முயற்சிக்கவும்!"
+ காணொளி 40MB க்கும் குறைவாக இருக்க வேண்டும்.
+ டூத் அனுப்ப இயலவில்லை
+
+ நேரடி தகவல்
+ பட்டைகள்
+ பொருத்தப்பட்டது
+ 1 நாள்
+ 3 நாட்கள்
+ 7 நாட்கள்
+ விருப்பத்தைச் சேர்
+
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 2f80e6b34..496716f5a 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -26,7 +26,6 @@
Direkt Mesajlar
Sekmeler
İleti
- #%s
İletiler
Yanıtlar
Sabitlenmiş
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 716ea0fd9..f9d99ce66 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -27,7 +27,6 @@
私信
标签页
嘟文
- #%s
嘟文
嘟文和回复
已置顶
@@ -459,9 +458,6 @@
剩余 %s
%s 结束
已结束
-
-
- <b>%1$d%%</b> %2$s
投票
diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml
index c8dd30a4d..d3b349a48 100644
--- a/app/src/main/res/values-zh-rHK/strings.xml
+++ b/app/src/main/res/values-zh-rHK/strings.xml
@@ -27,7 +27,6 @@
私信
標籤頁
嘟文
- #%s
嘟文
嘟文和回覆
已置頂
@@ -454,10 +453,7 @@
剩餘 %s
%s 結束
已結束
-
-
- <b>%1$d%%</b> %2$s
-
+
投票
你參與的投票已結束
diff --git a/app/src/main/res/values-zh-rMO/strings.xml b/app/src/main/res/values-zh-rMO/strings.xml
index c8dd30a4d..d3b349a48 100644
--- a/app/src/main/res/values-zh-rMO/strings.xml
+++ b/app/src/main/res/values-zh-rMO/strings.xml
@@ -27,7 +27,6 @@
私信
標籤頁
嘟文
- #%s
嘟文
嘟文和回覆
已置頂
@@ -454,10 +453,7 @@
剩餘 %s
%s 結束
已結束
-
-
- <b>%1$d%%</b> %2$s
-
+
投票
你參與的投票已結束
diff --git a/app/src/main/res/values-zh-rSG/strings.xml b/app/src/main/res/values-zh-rSG/strings.xml
index d07366ef0..a6926c9c2 100644
--- a/app/src/main/res/values-zh-rSG/strings.xml
+++ b/app/src/main/res/values-zh-rSG/strings.xml
@@ -27,7 +27,6 @@
私信
标签页
嘟文
- #%s
嘟文
嘟文和回复
已置顶
@@ -459,9 +458,6 @@
剩余 %s
%s 结束
已结束
-
-
- <b>%1$d%%</b> %2$s
投票
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 80b7cc935..5c18ca0aa 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -27,7 +27,6 @@
私信
標籤頁
嘟文
- #%s
嘟文
嘟文和回覆
已置頂
@@ -453,10 +452,7 @@
剩餘 %s
%s 結束
已結束
-
-
- <b>%1$d%%</b> %2$s
-
+
投票
你參與的投票已結束
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 34aeb80cf..f91fea547 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -12,8 +12,7 @@
-
-
+
@@ -29,7 +28,7 @@
-
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index cdd9ff025..378090440 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -19,7 +19,6 @@
#ffffff
#d9e1e8
#9baec8
- #4c5368
#d9e1e8
#444b5d
#2f3441
@@ -46,7 +45,6 @@
#CC000000
#3c3c3c
#5f636f
- #f6f7f7
#7C000000
#BFBFBF
#b0b0b0
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index a5ba6214d..f8bbe3d48 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -40,8 +40,13 @@
4.5dp
3dp
160dp
+ 14dp
+
5dp
12dp
+
+ 72dp
+ 108dp
diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml
index 79ba6a22e..4a69fdb42 100644
--- a/app/src/main/res/values/donottranslate.xml
+++ b/app/src/main/res/values/donottranslate.xml
@@ -1,7 +1,7 @@
- Yuito
- https://accelf.net/yuito
+ https://accelf.net/yuito
+ %1$s %2$s
oauth2redirect
com.keylesspalace.tusky.PREFERENCES
@@ -9,6 +9,7 @@
<b>%1$s</b><br>%2$s
\@
#
+ #%s
:%s:
@@ -130,5 +131,5 @@
- 604800
-
+ <b>%1$d%%</b>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7f3b8e238..db5818601 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -30,7 +30,6 @@
Direct Messages
Tabs
Toot
- #%s
Notestock
Posts
With replies
@@ -297,6 +296,7 @@
About
Yuito %s
+ Powered by Tusky
Yuito is free and open-source software.
It is licensed under the GNU General Public License Version 3.
You can view the license here: https://www.gnu.org/licenses/gpl-3.0.en.html
@@ -510,8 +510,6 @@
%s left
ends at %s
closed
-
- <b>%1$d%%</b> %2$s
Vote
@@ -564,5 +562,6 @@
Multiple choices
Choice %d
Edit
+ Error looking up post %s
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index c19c81782..18ef8584c 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -63,6 +63,8 @@
- @color/color_primary_dark_light
+ - @style/Widget.MaterialComponents.AppBarLayout.Surface
+
- @color/color_background_light
- @color/color_primary_light
- @color/window_background_light
@@ -77,10 +79,9 @@
- @color/window_background_light
- @color/custom_tab_toolbar_light
- - @color/toolbar_background_light
- - @color/toolbar_icon_light
+ - @color/toolbar_icon_light
- @style/TuskyImageButton.Light
- - @drawable/ic_reblog_light_18dp
+ - @drawable/ic_reblog_light_24dp
- @drawable/reblog_inactive_light
- @drawable/reblog_private_light
- @drawable/reblog_unleakable_light
@@ -98,7 +99,7 @@
- @drawable/conversation_thread_line_light
- @color/tusky_blue
- - @drawable/tab_page_margin_light
+ - @color/tab_page_margin_light
- @color/color_primary_dark_light
- @color/toolbar_icon_dark
@@ -159,9 +160,6 @@
- ?attr/status_text_medium
- true
- 3dp
- - ?attr/tab_icon_selected_tint
- - ?android:attr/textColorSecondary
- - ?attr/tab_icon_selected_tint
diff --git a/app/src/main/res/xml/share_shortcuts.xml b/app/src/main/res/xml/share_shortcuts.xml
new file mode 100644
index 000000000..54ecd5db1
--- /dev/null
+++ b/app/src/main/res/xml/share_shortcuts.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt
index 2db1cd0d7..da80f784a 100644
--- a/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt
@@ -214,6 +214,16 @@ class BottomSheetActivityTest {
Assert.assertEquals(nonMastodonQuery, activity.link)
}
+ @Test
+ fun search_withNoResults_appliesRequestedFallbackBehavior() {
+ for (fallbackBehavior in listOf(PostLookupFallbackBehavior.OPEN_IN_BROWSER, PostLookupFallbackBehavior.DISPLAY_ERROR)) {
+ activity.viewUrl(nonMastodonQuery, fallbackBehavior)
+ testScheduler.advanceTimeBy(100, TimeUnit.MILLISECONDS)
+ Assert.assertEquals(nonMastodonQuery, activity.link)
+ Assert.assertEquals(fallbackBehavior, activity.fallbackBehavior)
+ }
+ }
+
@Test
fun search_withCancellation_doesNotLoadUrl_forAccount() {
activity.viewUrl(accountQuery)
@@ -263,6 +273,7 @@ class BottomSheetActivityTest {
var statusId: String? = null
var accountId: String? = null
var link: String? = null
+ var fallbackBehavior: PostLookupFallbackBehavior? = null
init {
mastodonApi = api
@@ -282,5 +293,9 @@ class BottomSheetActivityTest {
this.statusId = statusId
}
+ override fun performUrlFallbackAction(url: String, fallbackBehavior: PostLookupFallbackBehavior) {
+ this.link = url
+ this.fallbackBehavior = fallbackBehavior
+ }
}
}
\ No newline at end of file
diff --git a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt
index 343ac1e15..c8a06252f 100644
--- a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt
@@ -26,14 +26,12 @@ import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.entity.Instance
import com.keylesspalace.tusky.network.MastodonApi
-import com.keylesspalace.tusky.util.ThemeUtils
import okhttp3.Request
import org.junit.Assert
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.robolectric.Robolectric
@@ -51,14 +49,13 @@ import retrofit2.Response
* Created by charlag on 3/7/18.
*/
-@Config(application = FakeTuskyApplication::class)
+@Config(application = FakeTuskyApplication::class, sdk = [28])
@RunWith(AndroidJUnit4::class)
class ComposeActivityTest {
private lateinit var activity: ComposeActivity
private lateinit var accountManagerMock: AccountManager
private lateinit var apiMock: MastodonApi
- private lateinit var themeUtilsMock: ThemeUtils
private val account = AccountEntity(
id = 1,
@@ -85,9 +82,9 @@ class ComposeActivityTest {
val controller = Robolectric.buildActivity(ComposeActivity::class.java)
activity = controller.get()
- accountManagerMock = Mockito.mock(AccountManager::class.java)
+ accountManagerMock = mock(AccountManager::class.java)
- apiMock = Mockito.mock(MastodonApi::class.java)
+ apiMock = mock(MastodonApi::class.java)
`when`(apiMock.getCustomEmojis()).thenReturn(object: Call> {
override fun isExecuted(): Boolean {
return false
@@ -125,12 +122,9 @@ class ComposeActivityTest {
val dbMock = mock(AppDatabase::class.java)
`when`(dbMock.instanceDao()).thenReturn(instanceDaoMock)
- themeUtilsMock = Mockito.mock(ThemeUtils::class.java)
-
activity.mastodonApi = apiMock
activity.accountManager = accountManagerMock
activity.database = dbMock
- activity.themeUtils = themeUtilsMock
`when`(accountManagerMock.activeAccount).thenReturn(account)
@@ -185,7 +179,7 @@ class ComposeActivityTest {
fun whenTextContainsNoUrl_everyCharacterIsCounted() {
val content = "This is test content please ignore thx "
insertSomeTextInContent(content)
- Assert.assertEquals(activity.calculateTextLength(), content.length)
+ assertEquals(activity.calculateTextLength(), content.length)
}
@Test
@@ -193,7 +187,7 @@ class ComposeActivityTest {
val url = "https://www.google.dk/search?biw=1920&bih=990&tbm=isch&sa=1&ei=bmDrWuOoKMv6kwWOkIaoDQ&q=indiana+jones+i+hate+snakes+animated&oq=indiana+jones+i+hate+snakes+animated&gs_l=psy-ab.3...54174.55443.0.55553.9.7.0.0.0.0.255.333.1j0j1.2.0....0...1c.1.64.psy-ab..7.0.0....0.40G-kcDkC6A#imgdii=PSp15hQjN1JqvM:&imgrc=H0hyE2JW5wrpBM:"
val additionalContent = "Check out this @image #search result: "
insertSomeTextInContent(additionalContent + url)
- Assert.assertEquals(activity.calculateTextLength(), additionalContent.length + ComposeActivity.MAXIMUM_URL_LENGTH)
+ assertEquals(activity.calculateTextLength(), additionalContent.length + ComposeActivity.MAXIMUM_URL_LENGTH)
}
@Test
diff --git a/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt b/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt
index c99effea7..640f6826b 100644
--- a/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt
@@ -16,6 +16,10 @@ class FakeTuskyApplication : TuskyApplication() {
// No-op
}
+ override fun initNightMode() {
+ // No-op
+ }
+
override fun getServiceLocator(): ServiceLocator {
return locator
}
diff --git a/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt b/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt
index 704586442..b7e95dc16 100644
--- a/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt
@@ -24,7 +24,7 @@ import retrofit2.Callback
import retrofit2.Response
import java.util.*
-@Config(application = FakeTuskyApplication::class)
+@Config(application = FakeTuskyApplication::class, sdk = [28])
@RunWith(AndroidJUnit4::class)
class FilterTest {
@@ -37,7 +37,6 @@ class FilterTest {
val activity = controller.get()
activity.accountManager = mock()
- activity.themeUtils = mock()
val apiMock = Mockito.mock(MastodonApi::class.java)
Mockito.`when`(apiMock.getFilters()).thenReturn(object: Call> {
override fun isExecuted(): Boolean {
diff --git a/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt b/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt
index f90a95e7e..66bf73e80 100644
--- a/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt
@@ -100,15 +100,10 @@ class SpanUtilsTest {
spans.add(BoundedSpan(what, start, end))
}
- override fun getSpans(start: Int, end: Int, type: Class?): Array {
- val matching = if (type == null) {
- ArrayList()
- } else {
- spans.filter { it.start >= start && it.end <= end && type.isAssignableFrom(it.span?.javaClass) }
+ override fun getSpans(start: Int, end: Int, type: Class): Array {
+ return spans.filter { it.start >= start && it.end <= end && type.isInstance(it)}
.map { it.span }
- .let { ArrayList(it) }
- }
- return matching.toArray() as Array
+ .toTypedArray() as Array
}
override fun removeSpan(what: Any?) {
diff --git a/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt b/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt
index f11658b00..acb6cf881 100644
--- a/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt
+++ b/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt
@@ -9,7 +9,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
-@Config(application = FakeTuskyApplication::class)
+@Config(application = FakeTuskyApplication::class, sdk = [28])
@RunWith(AndroidJUnit4::class)
class SmartLengthInputFilterTest {
diff --git a/build.gradle b/build.gradle
index 98df4e943..265660c6f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,8 +7,8 @@ buildscript {
google()
}
dependencies {
- classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta06'
- classpath 'com.android.tools.build:gradle:3.5.0'
+ classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta07'
+ classpath 'com.android.tools.build:gradle:3.5.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
diff --git a/fastlane/metadata/android/bn_IN/changelogs/67.txt b/fastlane/metadata/android/bn_IN/changelogs/67.txt
new file mode 100644
index 000000000..249433061
--- /dev/null
+++ b/fastlane/metadata/android/bn_IN/changelogs/67.txt
@@ -0,0 +1,9 @@
+টাস্কি v9.0
+
+- আপনি এখন টাস্কি থেকে পোল তৈরি করতে পারেন
+- উন্নত অনুসন্ধান
+- সর্বদা সামগ্রীর সতর্কতাগুলি প্রসারিত করতে অ্যাকাউন্ট পছন্দগুলিতে নতুন বিকল্প
+- নেভিগেশন ড্রয়ারের অবতারগুলিতে এখন একটি বৃত্তাকার বর্গাকার আকার রয়েছে
+- ব্যবহারকারীরা কোনও স্ট্যাটাস কখনও পোস্ট না করলেও এখন তাদের প্রতিবেদন করা সম্ভব
+- টস্কি এখন অ্যান্ড্রয়েড 6+ এ ক্লিয়ারটেক্সট সংযোগের মাধ্যমে সংযোগ দিতে অস্বীকার করবে
+- অন্যান্য অনেক ছোট উন্নতি এবং বাগ ফিক্স
diff --git a/fastlane/metadata/android/cs/changelogs/61.txt b/fastlane/metadata/android/cs/changelogs/61.txt
new file mode 100644
index 000000000..83137cbed
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/61.txt
@@ -0,0 +1,7 @@
+Tusky v7.0
+
+- Podpora pro zobrazování anket, hlasování a oznámení o anketách
+- Nová tlačítka pro filtrování v panelu oznámení a smazání všech oznámení
+- Smažte a přepište své vlastní tooty
+- Nový indikátor na obrázku profilu, který ukazuje, jestli je účet robot (může být vypnut v nastavení)
+- Nové překlady: norština (bokmål) a slovinština.
diff --git a/fastlane/metadata/android/cs/changelogs/67.txt b/fastlane/metadata/android/cs/changelogs/67.txt
new file mode 100644
index 000000000..0db8b0f6f
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/67.txt
@@ -0,0 +1,9 @@
+Tusky v9.0
+
+- Nyní můžete z Tuskyho vytvářet ankety
+- Vylepšené vyhledávání
+- Nová možnost v nastavení účtu umožňuje vždy rozbalovat varování o obsahu
+- Avatary v navigačním menu mají nyní zakulacené rohy
+- Je nyní možné nahlašovat uživatele i pokud ještě nenapsali žádný příspěvek
+- Tusky bude odteď odmítat cleartextová spojení na Androidu 6+
+- Spousta dalších malých vylepšení a oprav chyb
diff --git a/fastlane/metadata/android/cs/changelogs/68.txt b/fastlane/metadata/android/cs/changelogs/68.txt
new file mode 100644
index 000000000..db891085a
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/68.txt
@@ -0,0 +1,3 @@
+Tusky v9.1
+
+Toto vydání zajišťuje kompatibilitu s Mastodonem 3 a vylepšuje výkon a stabilitu.
diff --git a/fastlane/metadata/android/cs/full_description.txt b/fastlane/metadata/android/cs/full_description.txt
new file mode 100644
index 000000000..3b364d389
--- /dev/null
+++ b/fastlane/metadata/android/cs/full_description.txt
@@ -0,0 +1,12 @@
+Tusky je lehký klient pro Mastodon, svobodný a otevřený server pro sociální síť.
+
+• Material Design
+• Implementována většina API Mastodonu
+• Podpora více účtů
+• Tmavý a světlý motiv s možností automatického přepínání podle denní doby
+• Koncepty – komponujte tooty a uložte je na později
+• Vyberte si mezi různými styly emoji
+• Optimalizováno pro obrazovky všech velikostí
+• Zcela otevřený kód – žádný nesvobodný provázaný software jako služby Google
+
+Chcete-li o Mastodonu vědět více, navštivte https://joinmastodon.org/
diff --git a/fastlane/metadata/android/cs/short_description.txt b/fastlane/metadata/android/cs/short_description.txt
new file mode 100644
index 000000000..99eacd255
--- /dev/null
+++ b/fastlane/metadata/android/cs/short_description.txt
@@ -0,0 +1 @@
+Víceúčtový klient pro sociální síť Mastodon
diff --git a/fastlane/metadata/android/cs/title.txt b/fastlane/metadata/android/cs/title.txt
new file mode 100644
index 000000000..0238ffc0a
--- /dev/null
+++ b/fastlane/metadata/android/cs/title.txt
@@ -0,0 +1 @@
+Tusky
diff --git a/fastlane/metadata/android/de/changelogs/67.txt b/fastlane/metadata/android/de/changelogs/67.txt
new file mode 100644
index 000000000..c0ee1d24c
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/67.txt
@@ -0,0 +1,9 @@
+Tusky v9.0
+
+- Du kannst jetzt Umfragen erstellen
+- Die Suche wurde verbessert
+- Neue Option in den Profileinstellungen, um Inhaltswarnungen immer auszuklappen
+- Avatare im Hauptmenü haben jetzt abgerundete Ecken
+- Es ist jetzt möglich, Profile ohne Beiträge zu melden
+- Tusky wird auf Android 6+ nur noch sichere Netzwerkverbindungen nutzen
+- Viele andere kleine Verbesserungen und Fehlerkorrekturen
diff --git a/fastlane/metadata/android/eu/changelogs/58.txt b/fastlane/metadata/android/eu/changelogs/58.txt
new file mode 100644
index 000000000..5e5cb67ce
--- /dev/null
+++ b/fastlane/metadata/android/eu/changelogs/58.txt
@@ -0,0 +1,9 @@
+Tusky v6.0
+
+- Kronikaren iragazkiak Kontuen Hobespenetara aldatu dira eta zerbitzariarekin sinkronizatuko dira
+- Orain interfaze nagusian traola pertsonalizatu bat izan dezakezu
+- Zerrendak horain editatu daitezke
+- Segurtasuna: TLS 1.0 eta TLS 1.1 sistemetarako laguntza kendu eta TLS 1.3-ren laguntza gehitu da Android 6+ bertsioan
+- Konposatutako ikuspegiak emoji pertsonalizatuak proposatzen ditu idazten hastean
+- Ezarpen berria "jarraitu sistemaren gaia"
+- Kronologiaren irisgarritasuna hobetu
diff --git a/fastlane/metadata/android/eu/changelogs/61.txt b/fastlane/metadata/android/eu/changelogs/61.txt
new file mode 100644
index 000000000..4881066cd
--- /dev/null
+++ b/fastlane/metadata/android/eu/changelogs/61.txt
@@ -0,0 +1,7 @@
+Tusky v7.0
+
+- Inkestak, botoak eta inkestak jakinarazteko laguntza
+- Botoi berriak jakinarazpen fitxa iragazteko eta jakinarazpen guztiak ezabatzeko
+- Ezabatu eta berriro diseinatu zure toot-ak
+- Profil irudian kontua bot-a den erakusten duen adierazle berria (lehentasunetan desaktibatu daiteke)
+- Itzulpen berriak: Bokmål Norvegiera eta Esloveniera.
diff --git a/fastlane/metadata/android/eu/changelogs/67.txt b/fastlane/metadata/android/eu/changelogs/67.txt
new file mode 100644
index 000000000..4eb0df325
--- /dev/null
+++ b/fastlane/metadata/android/eu/changelogs/67.txt
@@ -0,0 +1,9 @@
+Tusky v9.0
+
+- Orain Tusky-tik inkestak sor ditzakezu
+- Bilaketa hobetua
+- Aukera berria Kontuen Hobespenetan beti edukien abisuak zabaltzeko
+- Nabigazioko tiraderaren avatarrek forma karratu biribildua dute orain
+- Horain posible da erabiltzaileen berri ematea inoiz egoera bat argitaratu ez dutenean ere
+- Tusky-k orain ukatu egingo du Android 6+ bertsioetako testu-konexioen bidez konektatzea
+- Beste hainbat hobekuntza txiki eta akats konponketa
diff --git a/fastlane/metadata/android/eu/changelogs/68.txt b/fastlane/metadata/android/eu/changelogs/68.txt
new file mode 100644
index 000000000..7296a7783
--- /dev/null
+++ b/fastlane/metadata/android/eu/changelogs/68.txt
@@ -0,0 +1,3 @@
+Tusky v9.1
+
+Argitalpen honek Mastodon 3-rekin bateragarritasuna bermatzen du eta errendimendua eta egonkortasuna hobetzen ditu.
diff --git a/fastlane/metadata/android/eu/full_description.txt b/fastlane/metadata/android/eu/full_description.txt
new file mode 100644
index 000000000..2b0899ca6
--- /dev/null
+++ b/fastlane/metadata/android/eu/full_description.txt
@@ -0,0 +1,12 @@
+Tusky bezero arina da Mastodonentzat, doako eta irekia den sare sozialen zerbitzarirako.
+
+• Material Design
+• Mastodon API gehienak inplementatu dira
+• Kontu anitzeko laguntza
+• Gai iluna eta argia eguneko orduaren arabera automatikoki aldatzeko aukerarekin
+• Zirriborroak - idatzi tootak eta gorde itzazu gerorako
+• Aukeratu emoji estilo desberdinen artean
+• Pantaila tamaina guztietarako optimizatua
+• Iturri guztiz irekiak - Google zerbitzuak bezalako doako menpekotasunik ez
+
+Mastodoni buruz gehiago jakiteko, bisitatu https://joinmastodon.org/
diff --git a/fastlane/metadata/android/eu/short_description.txt b/fastlane/metadata/android/eu/short_description.txt
new file mode 100644
index 000000000..021722f9a
--- /dev/null
+++ b/fastlane/metadata/android/eu/short_description.txt
@@ -0,0 +1 @@
+Mastodon sare sozialerako kontu anitzeko bezero bat
diff --git a/fastlane/metadata/android/eu/title.txt b/fastlane/metadata/android/eu/title.txt
new file mode 100644
index 000000000..0238ffc0a
--- /dev/null
+++ b/fastlane/metadata/android/eu/title.txt
@@ -0,0 +1 @@
+Tusky
diff --git a/fastlane/metadata/android/fa/changelogs/58.txt b/fastlane/metadata/android/fa/changelogs/58.txt
index 9eda8dd95..559815a74 100644
--- a/fastlane/metadata/android/fa/changelogs/58.txt
+++ b/fastlane/metadata/android/fa/changelogs/58.txt
@@ -1,11 +1,10 @@
-تاسکی نسخه ۶٫۰
+تاسکی نگارش ۶٫۰
-- صافیهای خطزمانی به ترجیحات حساب منتقل شده و با کارساز همگام خواهد شد
-- اکنون میتوانید هشتگ سفارشی را به عنوان یک زبانه در رابط اصلی داشته باشید
-- سیاههها میتوانند ویرایش شوند
-- امنیتی: حذف پشتیبانی برای TLS 1.0 و TLS 1.1، و افزودن پیشتیبانی برای TLS 1.3 روی اندروید ۶ به بالا
-- نمای ایجاد با شروع نگارش، شکلکهای سفارشی پیشنهاد میدهد
-- سبک جدید «پیروی از سبک سیستم» در تنظیمات
-- بهبود دسترسپذییری خطزمانی
+- پالایههای خط زمانی به ترجیحات حساب منتقل شده و با کارساز همگام خواهد شد
+- اکنون میتوانید برچسب سفارشی را به عنوان یک زبانه در رابط اصلی داشته باشید
+- فهرستها اکنون قابل ویرایشند
+- امنیت: حذف پشتیبانی برای TLS 1.0 و TLS 1.1، و افزودن پشتیبانی برای TLS 1.3 روی اندروید ۶ به بالا
+- نمای ایجاد با شروع نوشتن، اموجیهای سفارشی پیشنهاد میدهد
+- تنظیمات زمینهٔ جدید: «پیروی از سبک سامان»
+- بهبود دسترسپذیری خطزمانی
- تاسکی اکنون اعلانهای ناشناس را نادیده میگید و دیگر فرونمیپاشد
--
diff --git a/fastlane/metadata/android/fa/changelogs/61.txt b/fastlane/metadata/android/fa/changelogs/61.txt
index e666ddc28..462443a44 100644
--- a/fastlane/metadata/android/fa/changelogs/61.txt
+++ b/fastlane/metadata/android/fa/changelogs/61.txt
@@ -1,7 +1,7 @@
-تاسکی نسخه ۷٫۰
+تاسکی نگارش ۷٫۰
-- پشتیبانی از نمایش نظرسنجیها، رایها و اعلانهای مربوط به نظرسنجی
-- دکمه جدید برای از صافی گذراندن زبانه اعلان و برای پاک کردن همه اعلانها
-- امکان پاک کردن و بازنویسی بوقتان
-- علامت جدید روی تصویر نمایه که نشان میدهد یک حساب، بات است یا نه (قابل غیرفعالسازی در ترجیحات)
-- ترجمههای جدید: زبانهای نروژی و اسلونیایی.
+- پشتیبانی از نمایش نظرسنجیها، رأیها و آگاهیهای مربوط به نظرسنجی
+- دکمهٔ جدید برای پالایش زبانهٔ آگاهی و حذف همهٔ آگاهیها
+- حذف و بازنویسی بوقهای خودتان
+- نشانگر جدید روی تصویر نمایه که نشان میدهد یک حساب، بات است (قابل خاموش کردن در ترجیحات)
+- ترجمههای جدید: نروژی و اسلونیایی.
diff --git a/fastlane/metadata/android/fa/changelogs/67.txt b/fastlane/metadata/android/fa/changelogs/67.txt
index 41d522e10..f72402279 100644
--- a/fastlane/metadata/android/fa/changelogs/67.txt
+++ b/fastlane/metadata/android/fa/changelogs/67.txt
@@ -1,9 +1,9 @@
-تاسکی نسخه ۹٫۰
+تاسکی نگارش ۹٫۰
-- میتوانید داخل تاسکی، نظرسنجی ایجاد کنید
-- بهبود جستجو
-- گزینه جدید در ترجیحات حساب برای اینکه همواره بوقهای دارای محتوای حساس کامل نمایش داده شوند
-- آواتارها در کشوی ناوبری اکنون به صورت مربع دارای لبههای گرد دیده میشوند
-- اکنون امکان گزارش کاربرانی که هیچ بوقی ندارند فراهم شده است
-- تاسکی اکنون از اتصال غیر ایمن در اندروید ۶ سربازمیزند
-- به همراه بسیاری بهبودها و رفع اشکالات
+- اکنون میتوانید از تاسکی، نظرسنجی ایجاد کنید
+- جستوجوی بهبودیافته
+- گزینهٔ جدید در ترجیحات حساب برای گسترش همیشگی هشدارهای محتوا
+- آواتارها در کشوی ناوبری اکنون شکل مربّعی با لبههای گرد دارند
+- اکنون گزارش کاربرانی که هیچ بوقی ندارند نیز ممکن است
+- تاسکی اکنون روی اندروید ۶ به بالا از اتّصال غیر ایمن سر باز میزند
+- بسیاری از بهبودها و رفع اشکالهای دیگر
diff --git a/fastlane/metadata/android/fa/changelogs/68.txt b/fastlane/metadata/android/fa/changelogs/68.txt
index 56c36c0d1..e2710e78b 100644
--- a/fastlane/metadata/android/fa/changelogs/68.txt
+++ b/fastlane/metadata/android/fa/changelogs/68.txt
@@ -1,3 +1,3 @@
-تاسکی نسخه ۹٫۱
+تاسکی نگارش ۹٫۱
-این نسخه، سازگاری با ماستودون ۳ را تامین کرده و دارای بهبود عملکرد و پایداری است.
+این نگارش، سازگاری با ماستودون ۳ را تأمین کرده و عملکرد و پایداری را بهبود میدهد.
diff --git a/fastlane/metadata/android/fa/full_description.txt b/fastlane/metadata/android/fa/full_description.txt
index ca5520bda..c6b50a376 100644
--- a/fastlane/metadata/android/fa/full_description.txt
+++ b/fastlane/metadata/android/fa/full_description.txt
@@ -1,12 +1,12 @@
-تاسکی یک کارخواه سبک برای ماستودون (کارساز شبکه احتماعی آزاد و متنباز) است.
+تاسکی کارخواهی سبک برای ماستودون، یک کارساز شبکهٔ احتماعی نرمافزار آزاد است.
-• دارای طراحی متریال
-• اکثر APIهای ماستودون پیادهسازی شده است
+• طرّاحی متریال
+• پیادهسازی اکثر APIهای ماستودون
• پشتیبانی از چند حساب
-• پشتیبانی از سبک تیره و روشن با امکان تنظیم تغییر خودکار بر اساس ساعت روز
-• پشتیبانی از پیشنویس - امکان نوشتن بوقها و ذخیرهشان برای بعد
-• امکان انتخاب از بین انواع شکلک
-• بهینهسازیشده برای صفحههایی با اندازههای مختلف
-• کاملا آزاد و متنباز - بدون وابستگیهای غیرآزاد به خدمات گوگل
+• پشتیبانی از زمینهٔ تاریک و روشن با امکان تغییر خودکار بر اساس زمان روز
+• پیشنویسها - ایجاد بوقها و ذخیرهشان برای بعد
+• گزینش بین سبکهای مختلف اموجی
+• بهینهشده برای همهٔ اندازههای صفحه
+• کاملاُ نرمافزار آزاد - بدون وابستگیهای انحصاری مانند خدمات گوگل
-برای دریافت اطلاعات بیشتر درباره ماستودون https://joinmastodon.org را ببینید
+برای دریافت اطّلاعات بیشتر دربارهٔ ماستودون، https://joinmastodon.org را ببینید
diff --git a/fastlane/metadata/android/fa/short_description.txt b/fastlane/metadata/android/fa/short_description.txt
index 37ab16ac1..4dcadf70a 100644
--- a/fastlane/metadata/android/fa/short_description.txt
+++ b/fastlane/metadata/android/fa/short_description.txt
@@ -1 +1 @@
-یک کارخواه چندحسابی برای شبکه اجتماعی ماستودون
+کارخواهی چندحسابه برای شبکهٔ اجتماعی ماستودون
diff --git a/fastlane/metadata/android/fr/changelogs/58.txt b/fastlane/metadata/android/fr/changelogs/58.txt
new file mode 100644
index 000000000..fb6993c13
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/58.txt
@@ -0,0 +1,3 @@
+Tusky v6.0
+
+-
diff --git a/fastlane/metadata/android/fr/changelogs/67.txt b/fastlane/metadata/android/fr/changelogs/67.txt
new file mode 100644
index 000000000..1c1f62188
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/67.txt
@@ -0,0 +1,9 @@
+Tusky v9.0
+
+- Vous pouvez désormais 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
diff --git a/fastlane/metadata/android/fr/changelogs/68.txt b/fastlane/metadata/android/fr/changelogs/68.txt
new file mode 100644
index 000000000..ae5347589
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/68.txt
@@ -0,0 +1,3 @@
+Tusky v9.1
+
+Cette mise à jour assure la compatibilité avec Mastodon 3 et améliore les perfomances et la stabilité.
diff --git a/fastlane/metadata/android/hu/changelogs/68.txt b/fastlane/metadata/android/hu/changelogs/68.txt
new file mode 100644
index 000000000..b48118293
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/68.txt
@@ -0,0 +1,3 @@
+Tusky v9.1
+
+Ez a kiadás biztosítja a kompatibilitást a Mastodon 3-mal, valamint javítja a teljesítményt és a stabilitást.
diff --git a/fastlane/metadata/android/pl/changelogs/68.txt b/fastlane/metadata/android/pl/changelogs/68.txt
new file mode 100644
index 000000000..fc217ee14
--- /dev/null
+++ b/fastlane/metadata/android/pl/changelogs/68.txt
@@ -0,0 +1,3 @@
+Tusky v9.1
+
+Ta aktualizacja zapewnia kompatybilność z Mastodonem 3 i poprawia szybkość i stabilność aplikacji.
diff --git a/fastlane/metadata/android/pt_BR/changelogs/68.txt b/fastlane/metadata/android/pt_BR/changelogs/68.txt
new file mode 100644
index 000000000..917921132
--- /dev/null
+++ b/fastlane/metadata/android/pt_BR/changelogs/68.txt
@@ -0,0 +1,3 @@
+Tusky v9.1
+
+Esta atualização garante compatibilidade com Mastodon 3 e melhora a performance e estabilidade.
diff --git a/fastlane/metadata/android/ru/changelogs/58.txt b/fastlane/metadata/android/ru/changelogs/58.txt
new file mode 100644
index 000000000..008507490
--- /dev/null
+++ b/fastlane/metadata/android/ru/changelogs/58.txt
@@ -0,0 +1,10 @@
+Tusky v6.0
+
+- Фильтры ленты перенесены в настройки учетной записи и будут синхронизироваться с сервером.
+- Теперь вы можете иметь собственный хэштег-вкладку
+- Списки теперь можно редактировать
+- Безопасность: удалена поддержка TLS 1.0 и TLS 1.1, а также добавлена поддержка TLS 1.3 на Android 6+.
+- При составлении окна теперь будут предлагаться пользовательские смайлики.
+- Новая настройка темы "следовать теме системы"
+- Улучшена доступность ленты
+- Tusky теперь игнорирует неизвестные уведомления
diff --git a/fastlane/metadata/android/ru/changelogs/61.txt b/fastlane/metadata/android/ru/changelogs/61.txt
new file mode 100644
index 000000000..124bdfd9b
--- /dev/null
+++ b/fastlane/metadata/android/ru/changelogs/61.txt
@@ -0,0 +1,7 @@
+Tusky v7.0
+
+- Добавлена поддержка отображения опросов, голосования и уведомлений об опросе.
+- Новые кнопки для фильтрации вкладки уведомлений и удаления всех уведомлений
+- удалить и перерисовать свои собственные слова
+- новый индикатор, который показывает, является ли аккаунт ботом на изображении профиля (можно отключить в настройках)
+- Новые переводы: норвежский букмол и словенский.
diff --git a/fastlane/metadata/android/ru/changelogs/68.txt b/fastlane/metadata/android/ru/changelogs/68.txt
new file mode 100644
index 000000000..5c139e989
--- /dev/null
+++ b/fastlane/metadata/android/ru/changelogs/68.txt
@@ -0,0 +1,3 @@
+Tusky v9.1
+
+Этот релиз обеспечивает совместимость с Mastodon 3, повышает производительность и стабильность.
diff --git a/fastlane/metadata/android/sl/short_description.txt b/fastlane/metadata/android/sl/short_description.txt
new file mode 100644
index 000000000..c1b4b901f
--- /dev/null
+++ b/fastlane/metadata/android/sl/short_description.txt
@@ -0,0 +1 @@
+Odjemalec z več računi za socialno omrežje Mastodon
diff --git a/fastlane/metadata/android/sl/title.txt b/fastlane/metadata/android/sl/title.txt
new file mode 100644
index 000000000..0238ffc0a
--- /dev/null
+++ b/fastlane/metadata/android/sl/title.txt
@@ -0,0 +1 @@
+Tusky
diff --git a/fastlane/metadata/android/ta/short_description.txt b/fastlane/metadata/android/ta/short_description.txt
new file mode 100644
index 000000000..ae066270c
--- /dev/null
+++ b/fastlane/metadata/android/ta/short_description.txt
@@ -0,0 +1 @@
+மஸ்டொடான் சமூகத் தளத்திற்கான செயலி
diff --git a/fastlane/metadata/android/ta/title.txt b/fastlane/metadata/android/ta/title.txt
new file mode 100644
index 000000000..7b21ec113
--- /dev/null
+++ b/fastlane/metadata/android/ta/title.txt
@@ -0,0 +1 @@
+டஸ்க்கி
diff --git a/instance-build.gradle b/instance-build.gradle
new file mode 100644
index 000000000..e572df435
--- /dev/null
+++ b/instance-build.gradle
@@ -0,0 +1,19 @@
+/**
+Edit this file to create a Tusky build that is customized for your Fediverse instance.
+Note: Publishing a custom build on Google Play may violate the Google Play developer policy (Repetetive Content)
+ */
+
+// The app name
+ext.APP_NAME = "Yuito"
+
+// The application id. Must be unique, e.g. based on your domain
+ext.APP_ID = "net.accelf.yuito"
+
+// url of a custom app logo. Recommended size at least 600x600. Keep empty to use the Tusky elephant friend.
+ext.CUSTOM_LOGO_URL = ""
+
+// e.g. mastodon.social. Keep empty to not suggest any instance on the signup screen
+ext.CUSTOM_INSTANCE = ""
+
+// link to your support account. Will be linked on the about page when not empty.
+ext.SUPPORT_ACCOUNT_URL = "https://odakyu.app/@ars42525"
\ No newline at end of file