mirror of
https://github.com/accelforce/Yuito
synced 2025-02-01 16:36:50 +01:00
Merge remote-tracking branch 'tuskyapp/develop'
This commit is contained in:
commit
762b2225ca
@ -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).
|
||||
|
148
app/build.gradle
148
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'
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<shortcut
|
||||
android:icon="@mipmap/ic_shortcut_compose"
|
||||
android:shortcutId="com.keylesspalace.tusky.Compose"
|
||||
android:shortcutLongLabel="@string/compose_shortcut_long_label"
|
||||
android:shortcutShortLabel="@string/compose_shortcut_short_label">
|
||||
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:targetClass="com.keylesspalace.tusky.SplashActivity"
|
||||
android:targetPackage="com.keylesspalace.tusky"/>
|
||||
<intent
|
||||
android:action="com.keylesspalace.tusky.Compose"
|
||||
android:targetClass="com.keylesspalace.tusky.ComposeActivity"
|
||||
android:targetPackage="com.keylesspalace.tusky"/>
|
||||
|
||||
</shortcut>
|
||||
|
||||
</shortcuts>
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<shortcut
|
||||
android:icon="@mipmap/ic_shortcut_compose"
|
||||
android:shortcutId="com.keylesspalace.tusky.Compose"
|
||||
android:shortcutLongLabel="@string/compose_shortcut_long_label"
|
||||
android:shortcutShortLabel="@string/compose_shortcut_short_label">
|
||||
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:targetClass="com.keylesspalace.tusky.SplashActivity"
|
||||
android:targetPackage="com.keylesspalace.tusky.test"/>
|
||||
<intent
|
||||
android:action="com.keylesspalace.tusky.Compose"
|
||||
android:targetClass="com.keylesspalace.tusky.ComposeActivity"
|
||||
android:targetPackage="com.keylesspalace.tusky.test"/>
|
||||
|
||||
</shortcut>
|
||||
|
||||
</shortcuts>
|
@ -31,7 +31,8 @@
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.shortcuts"
|
||||
android:resource="@xml/shortcuts" />
|
||||
android:resource="@xml/share_shortcuts" />
|
||||
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".SavedTootActivity"
|
||||
@ -52,7 +53,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden">
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
|
||||
@ -91,7 +92,8 @@
|
||||
|
||||
<meta-data
|
||||
android:name="android.service.chooser.chooser_target_service"
|
||||
android:value="com.keylesspalace.tusky.service.AccountChooserService" />
|
||||
android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
|
||||
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ComposeActivity"
|
||||
@ -106,7 +108,7 @@
|
||||
android:theme="@style/TuskyBaseTheme" />
|
||||
<activity
|
||||
android:name=".AccountActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden" />
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|smallestScreenSize" />
|
||||
<activity android:name=".EditProfileActivity" />
|
||||
<activity android:name=".PreferencesActivity" />
|
||||
<activity android:name=".FavouritesActivity" />
|
||||
@ -153,16 +155,8 @@
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name=".service.SendTootService" />
|
||||
<service
|
||||
android:name=".service.AccountChooserService"
|
||||
android:label="@string/app_name"
|
||||
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE"
|
||||
tools:targetApi="23">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.chooser.ChooserTargetService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
@ -12,6 +12,7 @@ import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.util.CustomURLSpan
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
import kotlinx.android.synthetic.main.activity_about.*
|
||||
import kotlinx.android.synthetic.main.toolbar_basic.*
|
||||
import net.accelf.yuito.AccessTokenLoginActivity
|
||||
@ -34,7 +35,11 @@ class AboutActivity : BottomSheetActivity(), Injectable {
|
||||
onEasterEggExecute()
|
||||
}
|
||||
|
||||
versionTextView.text = getString(R.string.about_tusky_version, BuildConfig.VERSION_NAME)
|
||||
versionTextView.text = getString(R.string.about_app_version, getString(R.string.app_name), BuildConfig.VERSION_NAME)
|
||||
|
||||
if(BuildConfig.CUSTOM_INSTANCE.isBlank()) {
|
||||
aboutPoweredByTusky.hide()
|
||||
}
|
||||
|
||||
aboutLicenseInfoTextView.setClickableTextWithoutUnderlines(R.string.about_tusky_license)
|
||||
aboutWebsiteInfoTextView.setClickableTextWithoutUnderlines(R.string.about_project_site)
|
||||
@ -42,7 +47,7 @@ class AboutActivity : BottomSheetActivity(), Injectable {
|
||||
aboutBugsFeaturesInfoTextView.setClickableTextWithoutUnderlines(R.string.about_bug_feature_request_site)
|
||||
|
||||
tuskyProfileButton.setOnClickListener {
|
||||
onAccountButtonClick()
|
||||
viewUrl(BuildConfig.SUPPORT_ACCOUNT_URL, BuildConfig.SUPPORT_ACCOUNT_URL)
|
||||
}
|
||||
|
||||
aboutLicensesButton.setOnClickListener {
|
||||
@ -55,10 +60,6 @@ class AboutActivity : BottomSheetActivity(), Injectable {
|
||||
startActivityWithSlideInAnimation(Intent(this, AccessTokenLoginActivity::class.java))
|
||||
}
|
||||
|
||||
private fun onAccountButtonClick() {
|
||||
viewUrl("https://odakyu.app/@ars42525", getString(R.string.about_tusky_account))
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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<AppCredentials>, 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<String, String>()
|
||||
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<AccessToken> {
|
||||
override fun onResponse(call: Call<AccessToken>, response: Response<AccessToken>) {
|
||||
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
|
||||
|
@ -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<TabData> 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() {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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<AccountEntity>(context, R.layout.item_autocomplete_account) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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<PollViewHolder>() {
|
||||
@ -71,10 +72,7 @@ class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
|
||||
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
|
||||
|
@ -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] = "";
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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<Pair<Status, StatusViewData.Concrete>>()
|
||||
private val loadedNotestockStatuses = ArrayList<Pair<Status, StatusViewData.Concrete>>()
|
||||
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<Status, StatusViewData.Concrete>) {
|
||||
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<Status, StatusViewData.Concrete>) {
|
||||
|
@ -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<Account, RecyclerView.ViewHolder>(STATUS_COMPARATOR) {
|
||||
|
@ -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
|
||||
}
|
@ -28,7 +28,7 @@ import javax.inject.Inject
|
||||
|
||||
abstract class SearchFragment<T> : Fragment(),
|
||||
LinkListener, Injectable, SwipeRefreshLayout.OnRefreshListener {
|
||||
private var isSwipeToRefreshEnabled: Boolean = true
|
||||
|
||||
private var snackbarErrorRetry: Snackbar? = null
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelFactory
|
||||
|
@ -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<Pair<Status, StatusViewData.C
|
||||
}
|
||||
R.id.status_copy_link -> {
|
||||
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 -> {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -81,7 +81,6 @@ class AccountMediaFragment : BaseFragment(), RefreshableFragment, Injectable {
|
||||
private var currentCall: Call<List<Status>>? = null
|
||||
private val statuses = mutableListOf<Status>()
|
||||
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()
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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<Either<Placeholder, Status>> iterator = this.statuses.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Either<Placeholder, Status> item = iterator.next();
|
||||
if(item.isRight()) {
|
||||
if (item.isRight()) {
|
||||
Status status = item.asRight();
|
||||
if (status.getId().length() < topId.length() || status.getId().compareTo(topId) < 0) {
|
||||
|
||||
|
@ -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<Boolean>? = 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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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 <http://www.gnu.org/licenses>. */
|
||||
|
||||
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<Fragment> fragments = new SparseArray<>(TAB_COUNT);
|
||||
|
||||
private final Set<Integer> 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<getCount();i++){
|
||||
Fragment fragment = getFragment(i);
|
||||
if (fragment instanceof RefreshableFragment){
|
||||
((RefreshableFragment) fragment).refreshContent();
|
||||
}
|
||||
else{
|
||||
pagesToRefresh.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/* 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 <http://www.gnu.org/licenses>. */
|
||||
|
||||
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<WeakReference<Fragment>?>(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
|
||||
}
|
||||
}
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
@ -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<Attachment>,
|
||||
private val initialPosition: Int
|
||||
) : FragmentStatePagerAdapter(fragmentManager), SharedElementTransitionListener {
|
||||
) : ViewMediaAdapter(activity) {
|
||||
|
||||
private var primaryItem: ViewMediaFragment? = null
|
||||
private var didTransition = false
|
||||
private val fragments = MutableList<WeakReference<ViewMediaFragment>?>(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()
|
||||
}
|
||||
}
|
||||
|
@ -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<TabData>, manager: FragmentManager) : FragmentPagerAdapter(manager) {
|
||||
private val fragments = SparseArray<Fragment>(tabs.size)
|
||||
class MainPagerAdapter(val tabs: List<TabData>, activity: FragmentActivity) : FragmentStateAdapter(activity) {
|
||||
private val fragments = MutableList<WeakReference<Fragment>?>(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()
|
||||
}
|
||||
|
@ -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 <http://www.gnu.org/licenses>. */
|
||||
|
||||
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<ChooserTarget> {
|
||||
val targets = mutableListOf<ChooserTarget>()
|
||||
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
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses>. */
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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 <http://www.gnu.org/licenses>. */
|
||||
|
||||
@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()))
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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 <http://www.gnu.org/licenses>. */
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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(
|
||||
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="false" android:color="?attr/toolbar_icon_tint"/>
|
||||
<item android:state_selected="true" android:color="?attr/tab_icon_selected_tint"/>
|
||||
</selector>
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_primary_dark_dark" />
|
||||
<corners android:radius="14dp"/>
|
||||
<size android:height="100dp" android:width="100dp"/>
|
||||
</shape>
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_background_light" />
|
||||
<corners android:radius="14dp"/>
|
||||
<size android:height="100dp" android:width="100dp"/>
|
||||
</shape>
|
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z" />
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_reblog_active_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_reblog_active_24dp.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/tusky_blue"
|
||||
android:pathData="M17,2L17,5L5,5L5,11L7,11L7,7L17,7L17,10L21,6L17,2zM9.75,9.75L9.75,14.25L14.25,14.25L14.25,9.75L9.75,9.75zM17,13L17,17L7,17L7,14L3,18L7,22L7,19L19,19L19,13L17,13z"/>
|
||||
</vector>
|
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/tusky_blue"
|
||||
android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z"/>
|
||||
</vector>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/tab_page_margin_black" />
|
||||
</shape>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/tab_page_margin_dark" />
|
||||
</shape>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/tab_page_margin_light" />
|
||||
</shape>
|
@ -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">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="640dp"
|
||||
@ -45,16 +44,17 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/elephant_error"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/topProgressBar"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="parent"
|
||||
android:visibility="gone"/>
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
@ -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">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="640dp"
|
||||
@ -80,9 +79,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@android:color/transparent"
|
||||
android:visibility="gone"
|
||||
tools:src="@drawable/elephant_error"
|
||||
tools:visibility="visible" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
@ -1,20 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/tab_page_margin_drawable">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeRefreshLayout"
|
||||
android:layout_width="640dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="?attr/window_background">
|
||||
android:layout_gravity="center_horizontal">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/window_background"
|
||||
android:scrollbars="vertical" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textDirection="anyRtl"
|
||||
android:layout_gravity="center">
|
||||
android:layout_gravity="center"
|
||||
android:textDirection="anyRtl">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -46,11 +46,24 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="60dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/aboutPoweredByTusky"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:drawablePadding="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/about_powered_by_tusky"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/aboutLicenseInfoTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:hyphenationFrequency="full"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:paddingStart="@dimen/text_content_margin"
|
||||
android:paddingEnd="@dimen/text_content_margin"
|
||||
|
@ -17,16 +17,15 @@
|
||||
android:id="@+id/accountAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:colorBackground"
|
||||
android:elevation="@dimen/actionbar_elevation">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/collapsingToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:contentScrim="?attr/toolbar_background_color"
|
||||
app:contentScrim="?attr/colorSurface"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed"
|
||||
app:statusBarScrim="?android:attr/colorBackground"
|
||||
app:statusBarScrim="?attr/colorSurface"
|
||||
app:titleEnabled="false">
|
||||
|
||||
<ImageView
|
||||
@ -64,7 +63,6 @@
|
||||
android:layout_marginTop="6dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@ -174,7 +172,7 @@
|
||||
android:id="@+id/accountNoteTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:hyphenationFrequency="full"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:paddingTop="10dp"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
@ -196,6 +194,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:hyphenationFrequency="full"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:text="@string/label_remote_account"
|
||||
android:visibility="gone"
|
||||
@ -307,7 +306,6 @@
|
||||
android:textSize="?attr/status_text_medium" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!-- top margin equal to statusbar size will be set programmatically -->
|
||||
@ -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" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
@ -333,10 +333,11 @@
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/accountFragmentViewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/tab_page_margin_color"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
@ -355,11 +356,12 @@
|
||||
android:layout_width="@dimen/account_activity_avatar_size"
|
||||
android:layout_height="@dimen/account_activity_avatar_size"
|
||||
android:layout_marginStart="16dp"
|
||||
android:background="@drawable/avatar_background"
|
||||
android:padding="3dp"
|
||||
app:layout_anchor="@+id/accountHeaderInfoContainer"
|
||||
app:layout_anchorGravity="top"
|
||||
app:layout_scrollFlags="scroll"
|
||||
app:srcCompat="@drawable/avatar_default" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
@ -27,6 +27,7 @@
|
||||
android:layout_height="178dp"
|
||||
android:layout_marginBottom="50dp"
|
||||
android:contentDescription="@null"
|
||||
android:id="@+id/loginLogo"
|
||||
app:srcCompat="@drawable/elephant_friend" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -11,53 +11,43 @@
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" >
|
||||
android:layout_weight="1">
|
||||
|
||||
<RelativeLayout
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/main_appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false">
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="@dimen/actionbar_elevation">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/drawer_toggle"
|
||||
android:layout_width="?attr/actionBarSize"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="?android:colorBackground"
|
||||
android:contentDescription="@string/action_open_drawer"
|
||||
android:elevation="@dimen/actionbar_elevation"
|
||||
app:srcCompat="@drawable/ic_menu_24dp" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
style="@style/TuskyTabAppearance"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_toEndOf="@id/drawer_toggle"
|
||||
android:background="?android:colorBackground"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:elevation="@dimen/actionbar_elevation"
|
||||
app:tabGravity="fill"
|
||||
app:tabIconTint="@color/tab_icon_color"
|
||||
app:tabMaxWidth="0dp"
|
||||
app:tabMode="fixed"
|
||||
app:tabPaddingEnd="1dp"
|
||||
app:tabPaddingStart="1dp"
|
||||
app:tabPaddingTop="4dp"
|
||||
app:tabUnboundedRipple="false" />
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/pager"
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/main_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/tab_layout"
|
||||
android:layout_alignParentBottom="true" />
|
||||
app:contentInsetStartWithNavigation="0dp">
|
||||
|
||||
</RelativeLayout>
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
style="@style/TuskyTabAppearance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
app:tabGravity="fill"
|
||||
app:tabMaxWidth="0dp"
|
||||
app:tabMode="fixed"
|
||||
app:tabUnboundedRipple="false" />
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/tab_layout"
|
||||
android:background="?attr/tab_page_margin_color"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/floating_btn"
|
||||
@ -73,8 +63,9 @@
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<include layout="@layout/view_quick_toot"
|
||||
<include
|
||||
android:id="@+id/quick_toot_container"
|
||||
layout="@layout/view_quick_toot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0" />
|
||||
|
@ -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">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/toolbar_background_color"
|
||||
app:contentInsetStartWithNavigation="0dp"
|
||||
android:elevation="@dimen/actionbar_elevation"
|
||||
app:layout_scrollFlags="scroll|snap|enterAlways"
|
||||
app:navigationIcon="?attr/homeAsUpIndicator" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
style="@style/TuskyTabAppearance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/toolbar_background_color"
|
||||
app:tabGravity="fill"
|
||||
app:tabMode="fixed"
|
||||
app:tabTextAppearance="@style/TuskyTabAppearance"/>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pages"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -6,7 +6,7 @@
|
||||
android:background="@android:color/black"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.keylesspalace.tusky.view.ImageViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
@ -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">
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeRefreshLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:id="@+id/swipeRefreshLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
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"/>
|
||||
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" />
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
|
@ -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">
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeRefreshLayout"
|
||||
android:layout_width="match_parent"
|
||||
@ -29,23 +31,22 @@
|
||||
android:id="@+id/statusView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@android:color/transparent"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/elephant_error"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:id="@+id/topProgressBar"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:indeterminate="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="parent"
|
||||
android:visibility="gone"/>
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -58,7 +58,8 @@
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/window_background" />
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
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_gravity="center"
|
||||
@ -17,25 +17,26 @@
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_gravity="center" />
|
||||
android:layout_gravity="center"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mediaDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:background="#60000000"
|
||||
android:hyphenationFrequency="full"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:padding="8dp"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#eee"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
tools:text="Some media description" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -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" />
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
@ -2,9 +2,9 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/videoContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/videoContainer"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
@ -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"
|
||||
|
@ -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" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
@ -52,7 +53,8 @@
|
||||
android:textStyle="normal|bold"
|
||||
app:layout_constraintBottom_toTopOf="@id/notification_username"
|
||||
app:layout_constraintStart_toEndOf="@id/notification_avatar"
|
||||
app:layout_constraintTop_toTopOf="@id/notification_avatar"
|
||||
app:layout_constraintTop_toBottomOf="@id/notification_text"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="Test User" />
|
||||
|
||||
<TextView
|
||||
@ -64,7 +66,7 @@
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
app:layout_constraintBottom_toBottomOf="@id/notification_avatar"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/notification_avatar"
|
||||
app:layout_constraintTop_toBottomOf="@id/notification_display_name"
|
||||
tools:text="\@testuser" />
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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" />
|
||||
|
||||
|
||||
<ToggleButton
|
||||
android:id="@+id/notification_content_warning_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/notification_content_warning_description"
|
||||
android:layout_toEndOf="@id/notification_status_avatar"
|
||||
android:background="?attr/content_warning_button"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="150dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="4dp"
|
||||
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_warning_show_more"
|
||||
android:textOn="@string/status_content_warning_show_less"
|
||||
@ -109,6 +109,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/notification_content_warning_button"
|
||||
android:layout_toEndOf="@+id/notification_status_avatar"
|
||||
android:hyphenationFrequency="full"
|
||||
android:lineSpacingMultiplier="1.1"
|
||||
android:paddingBottom="10dp"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
@ -117,25 +118,25 @@
|
||||
|
||||
|
||||
<ToggleButton
|
||||
android:id="@+id/button_toggle_notification_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/notification_status_avatar"
|
||||
android:layout_below="@id/notification_content"
|
||||
android:textOff="@string/status_content_show_less"
|
||||
android:textOn="@string/status_content_show_more"
|
||||
android:background="?attr/content_warning_button"
|
||||
android:minHeight="0dp"
|
||||
android:minWidth="150dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
android:visibility="gone" />
|
||||
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" />
|
||||
|
||||
<include
|
||||
android:id="@+id/status_quote_inline_container"
|
||||
@ -151,13 +152,13 @@
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_below="@id/notification_top_text"
|
||||
android:layout_marginBottom="14dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:layout_marginRight="14dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="14dp"
|
||||
android:contentDescription="@string/action_view_profile"
|
||||
android:paddingBottom="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:scaleType="centerCrop"
|
||||
tools:ignore="RtlHardcoded,RtlSymmetry"
|
||||
tools:src="@drawable/avatar_default" />
|
||||
@ -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" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -12,8 +12,7 @@
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/toolbar_background_color" />
|
||||
android:layout_height="?attr/actionBarSize" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="title_direct_messages">الرسائل المباشرة</string>
|
||||
<string name="title_tab_preferences">الألسنة</string>
|
||||
<string name="title_view_thread">تبويق</string>
|
||||
<string name="title_tag">#%s</string>
|
||||
<string name="title_statuses">المشاركات</string>
|
||||
<string name="title_statuses_with_replies">يحتوي على ردود</string>
|
||||
<string name="title_statuses_pinned">مدبّس</string>
|
||||
@ -483,4 +482,12 @@
|
||||
|
||||
<string name="filter_dialog_whole_word_description">عندما تكون الكلمة أو العبارة أبجدية رقمية فقط ، فلن يتم تطبيقها إلا إذا كانت مطابقة للكلمة بأكملها</string>
|
||||
<string name="poll_info_format"> <!-- 15 votes • 1 hour left --> %1$s • %2$s</string>
|
||||
</resources>
|
||||
<string name="title_scheduled_toot">التبويقات المبَرمَجة</string>
|
||||
<string name="action_edit">تعديل</string>
|
||||
<string name="action_access_scheduled_toot">التبويقات المبَرمَجة</string>
|
||||
<string name="action_schedule_toot">برمجة تبويق</string>
|
||||
<string name="action_reset_schedule">صفّر</string>
|
||||
<string name="hint_configure_scheduled_toot">اضغط هنا لضبط برمجة التبويق.</string>
|
||||
<string name="post_lookup_error_format">خطأ أثناء البحث عن منشور %s</string>
|
||||
|
||||
</resources>
|
||||
|
@ -28,7 +28,6 @@
|
||||
<string name="title_direct_messages">সরাসরি বার্তা</string>
|
||||
<string name="title_tab_preferences">ট্যাবগুলি</string>
|
||||
<string name="title_view_thread">টুট</string>
|
||||
<string name="title_tag">#%s</string>
|
||||
<string name="title_statuses">পোস্টগুলি</string>
|
||||
<string name="title_statuses_with_replies">উত্তরের সাথে</string>
|
||||
<string name="title_statuses_pinned">পিন করা</string>
|
||||
@ -440,7 +439,6 @@
|
||||
<string name="poll_info_time_relative">%s বাকি</string>
|
||||
<string name="poll_info_time_absolute">%s এ শেষ হবে</string>
|
||||
<string name="poll_info_closed">বন্ধ</string>
|
||||
<string name="poll_option_format"> <!-- ১৫% এতে ভোট দিয়েছে! --> <b>%1$d%%</b> %2$s</string>
|
||||
|
||||
<string name="poll_vote">ভোট</string>
|
||||
|
||||
@ -505,4 +503,13 @@
|
||||
<string name="poll_new_choice_hint">পছন্দ %d</string>
|
||||
<string name="edit_poll">সম্পাদন</string>
|
||||
|
||||
<string name="title_scheduled_toot">নির্ধারিত টুটগুলি</string>
|
||||
<string name="action_edit">সম্পাদন</string>
|
||||
<string name="action_access_scheduled_toot">নির্ধারিত টুটগুলি</string>
|
||||
<string name="action_schedule_toot">নির্ধারিত টুট</string>
|
||||
<string name="action_reset_schedule">রিসেট</string>
|
||||
<string name="hint_configure_scheduled_toot">নির্ধারিত টুট কনফিগার করতে এখানে আলতো চাপুন।</string>
|
||||
<string name="about_powered_by_tusky">টাস্কি দ্বারা চালিত</string>
|
||||
<string name="post_lookup_error_format">%s পোস্ট অনুসন্ধানে ত্রুটি</string>
|
||||
|
||||
</resources>
|
||||
|
@ -23,7 +23,6 @@
|
||||
<string name="title_public_local">Local</string>
|
||||
<string name="title_public_federated">Federació</string>
|
||||
<string name="title_view_thread">Toot</string>
|
||||
<string name="title_tag">#%s</string>
|
||||
<string name="title_statuses">Posts</string>
|
||||
<string name="title_follows">Seguits</string>
|
||||
<string name="title_followers">Seguidors</string>
|
||||
@ -465,7 +464,6 @@
|
||||
</plurals>
|
||||
|
||||
<string name="description_status_cw">Advertència: %s</string>
|
||||
<string name="poll_option_format"> <!-- 15% vota aquesta acció! --> <b>%1$d%%</b> %2$s</string>
|
||||
|
||||
<string name="title_statuses_pinned">Toot fixat</string>
|
||||
<string name="unpin_action">Toot no fixat</string>
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="title_direct_messages">Přímé zprávy</string>
|
||||
<string name="title_tab_preferences">Panely</string>
|
||||
<string name="title_view_thread">Toot</string>
|
||||
<string name="title_tag">#%s</string>
|
||||
<string name="title_statuses">Tooty</string>
|
||||
<string name="title_statuses_with_replies">S odpověďmi</string>
|
||||
<string name="title_statuses_pinned">Připnuté</string>
|
||||
@ -392,7 +391,6 @@
|
||||
<string name="poll_info_time_relative">zbývá %s</string>
|
||||
<string name="poll_info_time_absolute">končí v %s</string>
|
||||
<string name="poll_info_closed">uzavřena</string>
|
||||
<string name="poll_option_format"> <!-- 15% vote for this! --> <b>%1$d%%</b> %2$s</string>
|
||||
|
||||
<string name="poll_vote">Hlasovat</string>
|
||||
|
||||
@ -466,4 +464,19 @@
|
||||
<string name="poll_new_choice_hint">Možnost %d</string>
|
||||
<string name="edit_poll">Upravit</string>
|
||||
|
||||
<string name="title_scheduled_toot">Plánované tooty</string>
|
||||
<string name="action_edit">Upravit</string>
|
||||
<string name="action_add_poll">Přidat anketu</string>
|
||||
<string name="action_access_scheduled_toot">Plánované tooty</string>
|
||||
<string name="action_schedule_toot">Naplánovat toot</string>
|
||||
<string name="action_reset_schedule">Obnovit</string>
|
||||
<string name="hint_configure_scheduled_toot">Klepnutím sem nastavíte plánovaný toot.</string>
|
||||
<string name="pref_title_alway_open_spoiler">Vždy rozbalovat tooty označené varováními o obsahu</string>
|
||||
<string name="filter_dialog_whole_word">Celé slovo</string>
|
||||
<string name="filter_dialog_whole_word_description">Je-li klíčové slovo nebo fráze pouze alfanumerická, bude použita pouze, pokud odpovídá celému slovu</string>
|
||||
<string name="title_accounts">Účty</string>
|
||||
<string name="failed_search">Hledání selhalo</string>
|
||||
|
||||
<string name="post_lookup_error_format">Chyba při hledání příspěvku %s</string>
|
||||
|
||||
</resources>
|
||||
|
@ -278,7 +278,6 @@
|
||||
<string name="error_network">Digwyddodd gwall rhwydwaith! Gwiriwch eich cysylltiad a cheisiwch eto!</string>
|
||||
<string name="title_direct_messages">Negeseuon Uniongyrchol</string>
|
||||
<string name="title_tab_preferences">Tabiau</string>
|
||||
<string name="title_tag">#%s</string>
|
||||
<string name="title_statuses_pinned">Wedi\'i binio</string>
|
||||
<string name="title_domain_mutes">Parthau cudd</string>
|
||||
<string name="message_empty">Dim byd yma.</string>
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="title_direct_messages">Direktnachrichten</string>
|
||||
<string name="title_tab_preferences">Tabs</string>
|
||||
<string name="title_view_thread">Unterhaltung</string>
|
||||
<string name="title_tag">#%s</string>
|
||||
<string name="title_statuses">Beiträge</string>
|
||||
<string name="title_statuses_with_replies">mit Antworten</string>
|
||||
<string name="title_statuses_pinned">Angeheftet</string>
|
||||
@ -376,7 +375,6 @@
|
||||
<string name="poll_info_time_relative">%s verbleibend</string>
|
||||
<string name="poll_info_time_absolute">endet um %s</string>
|
||||
<string name="poll_info_closed">Geschlossen</string>
|
||||
<string name="poll_option_format"> <b>%1$d%%</b> %2$s</string>
|
||||
|
||||
<string name="poll_vote">Abstimmen</string>
|
||||
|
||||
@ -448,4 +446,11 @@
|
||||
<string name="add_poll_choice">Auswahlmöglichkeit hinzufügen</string>
|
||||
<string name="poll_allow_multiple_choices">Mehrere Möglichkeiten</string>
|
||||
<string name="poll_new_choice_hint">Möglichkeit %d</string>
|
||||
<string name="title_scheduled_toot">Geplante Beiträge</string>
|
||||
<string name="action_edit">Editieren</string>
|
||||
<string name="action_access_scheduled_toot">Geplante Beiträge</string>
|
||||
<string name="action_schedule_toot">Plane Beitrag</string>
|
||||
<string name="action_reset_schedule">Zurücksetzen</string>
|
||||
<string name="hint_configure_scheduled_toot">Drücke hier, um den geplanten Beitrag zu konfigurieren.</string>
|
||||
<string name="abbreviated_in_years">Dies sind Zeitstempel für Status. Beispiele: \"16s\" oder \"2t\".</string>
|
||||
</resources>
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="title_direct_messages">Rektaj mesaĝoj</string>
|
||||
<string name="title_tab_preferences">Langetoj</string>
|
||||
<string name="title_view_thread">Mesaĝo</string>
|
||||
<string name="title_tag">#%s</string>
|
||||
<string name="title_statuses">Mesaĝoj</string>
|
||||
<string name="title_statuses_with_replies">Kun respondoj</string>
|
||||
<string name="title_statuses_pinned">Alpinglitaj</string>
|
||||
@ -391,7 +390,6 @@
|
||||
<string name="poll_info_time_relative">%s restas</string>
|
||||
<string name="poll_info_time_absolute">finiĝos je %s</string>
|
||||
<string name="poll_info_closed">finiĝita</string>
|
||||
<string name="poll_option_format"> <!-- 15% vote for this! --> <b>%1$d%%</b> %2$s</string>
|
||||
|
||||
<string name="poll_vote">Voĉdoni</string>
|
||||
|
||||
|
@ -18,15 +18,14 @@
|
||||
<string name="error_media_download_permission">Se requiere permiso para descargar al almacenamiento.</string>
|
||||
<string name="error_media_upload_image_or_video">No se pueden adjuntar imágenes y vídeos en el mismo estado.</string>
|
||||
<string name="error_media_upload_sending">La subida falló.</string>
|
||||
<string name="error_sender_account_gone">Error al publicar.</string>
|
||||
<string name="error_sender_account_gone">Error al enviar estado.</string>
|
||||
<string name="title_home">Inicio</string>
|
||||
<string name="title_notifications">Notificaciones</string>
|
||||
<string name="title_public_local">Local</string>
|
||||
<string name="title_public_federated">Federada</string>
|
||||
<string name="title_direct_messages">Mensajes Directos</string>
|
||||
<string name="title_tab_preferences">Pestañas</string>
|
||||
<string name="title_view_thread">Publicación</string>
|
||||
<string name="title_tag">#%s</string>
|
||||
<string name="title_view_thread">Estado</string>
|
||||
<string name="title_statuses">Estados</string>
|
||||
<string name="title_statuses_with_replies">Con respuestas</string>
|
||||
<string name="title_statuses_pinned">Fijado</string>
|
||||
@ -50,8 +49,8 @@
|
||||
<string name="status_content_show_less">Ocultar</string>
|
||||
<string name="message_empty">Nada aquí.</string>
|
||||
<string name="footer_empty">Nada por aquí. ¡Arrastra hacia abajo para recargar!</string>
|
||||
<string name="notification_reblog_format">%s impulsó tu toot</string>
|
||||
<string name="notification_favourite_format">%s marcó como favorito tu post</string>
|
||||
<string name="notification_reblog_format">%s impulsó tu estado</string>
|
||||
<string name="notification_favourite_format">%s marcó como favorito tu estado</string>
|
||||
<string name="notification_follow_format">%s te siguió</string>
|
||||
<string name="report_username_format">Reportar @%s</string>
|
||||
<string name="report_comment_hint">¿Información adicional?</string>
|
||||
@ -61,7 +60,7 @@
|
||||
<string name="action_favourite">Favorito</string>
|
||||
<string name="action_more">Más</string>
|
||||
<string name="action_compose">Redactar</string>
|
||||
<string name="action_login">Iniciar sesión</string>
|
||||
<string name="action_login">Iniciar sesión con Mastodon</string>
|
||||
<string name="action_logout">Cerrar sesión</string>
|
||||
<string name="action_logout_confirm">¿Seguro que quiere cerrar la sesión de %1$s?</string>
|
||||
<string name="action_follow">Seguir</string>
|
||||
@ -110,7 +109,7 @@
|
||||
<string name="action_open_as">Abrir como %s</string>
|
||||
<string name="action_share_as">Compartir como…</string>
|
||||
<string name="send_status_link_to">Compartir URL…</string>
|
||||
<string name="send_status_content_to">Compartir contenido…</string>
|
||||
<string name="send_status_content_to">Compartir estado…</string>
|
||||
<string name="send_media_to">Compartir medios a…</string>
|
||||
<string name="confirmation_reported">¡Enviado!</string>
|
||||
<string name="confirmation_unblocked">El usuario ya no está bloqueado</string>
|
||||
@ -143,7 +142,7 @@
|
||||
<string name="dialog_download_image">Descargar</string>
|
||||
<string name="dialog_message_cancel_follow_request">¿Cancelar petición de amistad?</string>
|
||||
<string name="dialog_unfollow_warning">¿Dejar de seguir esta cuenta?</string>
|
||||
<string name="dialog_delete_toot_warning">¿Eliminar este toot?</string>
|
||||
<string name="dialog_delete_toot_warning">¿Eliminar este estado\?</string>
|
||||
<string name="visibility_public">Público: Mostrar en historias públicas</string>
|
||||
<string name="visibility_unlisted">Oculto: No mostrar en historias públicas</string>
|
||||
<string name="visibility_private">Privado: Sólo visible para seguidores</string>
|
||||
@ -260,8 +259,8 @@
|
||||
<string name="lock_account_label_description">Tendrá que admitir los seguidores manualmente</string>
|
||||
<string name="compose_save_draft">¿Guardar borrador?</string>
|
||||
<string name="send_toot_notification_title">Enviando estado…</string>
|
||||
<string name="send_toot_notification_error_title">Error enviando estado</string>
|
||||
<string name="send_toot_notification_channel_name">Enviando estado</string>
|
||||
<string name="send_toot_notification_error_title">Error al enviar el estado</string>
|
||||
<string name="send_toot_notification_channel_name">Enviando estados</string>
|
||||
<string name="send_toot_notification_cancel_title">Envío cancelado</string>
|
||||
<string name="send_toot_notification_saved_content">Una copia del estado se ha guardado en borradores</string>
|
||||
<string name="action_compose_shortcut">Redactar</string>
|
||||
@ -370,7 +369,7 @@
|
||||
|
||||
<string name="downloading_media">Descargando contenido</string>
|
||||
|
||||
<string name="dialog_redraft_toot_warning">¿Borrar y devolver a borradores este toot\?</string>
|
||||
<string name="dialog_redraft_toot_warning">¿Borrar y devolver a borradores este estado\?</string>
|
||||
|
||||
<string name="pref_title_notification_filter_poll">encuestas que han terminado</string>
|
||||
<string name="notification_poll_description">Notificaciones sobre encuestas que han terminado</string>
|
||||
@ -416,8 +415,6 @@
|
||||
<string name="action_open_reblogger">Abrir autor del impulso</string>
|
||||
<string name="action_open_reblogged_by">Mostrar impulsos</string>
|
||||
|
||||
<string name="poll_option_format"> <!-- 15% vote for this! --> <b>%1$d%%</b> %2$s</string>
|
||||
|
||||
<string name="title_domain_mutes">Dominios ocultos</string>
|
||||
<string name="action_view_domain_mutes">Dominios ocultos</string>
|
||||
<string name="action_mute_domain">Silenciar %s</string>
|
||||
@ -445,7 +442,7 @@
|
||||
<string name="report_description_remote_instance">La cuenta es de otro servidor. ¿Enviar una copia anónima del reporte\?</string>
|
||||
|
||||
<string name="pref_title_show_notifications_filter">Mostrar filtro de notificaciones</string>
|
||||
<string name="pref_title_alway_open_spoiler">Mostrar siempre toots marcados con avisos de contenido</string>
|
||||
<string name="pref_title_alway_open_spoiler">Mostrar siempre estados marcados con avisos de contenido</string>
|
||||
<string name="title_accounts">Cuentas</string>
|
||||
<string name="failed_search">Error al buscar</string>
|
||||
|
||||
@ -463,4 +460,13 @@
|
||||
<string name="poll_new_choice_hint">Opción %d</string>
|
||||
<string name="edit_poll">Editar</string>
|
||||
|
||||
</resources>
|
||||
<string name="title_scheduled_toot">Estados programados</string>
|
||||
<string name="action_edit">Editar</string>
|
||||
<string name="action_access_scheduled_toot">Estados programados</string>
|
||||
<string name="action_schedule_toot">Programar estado</string>
|
||||
<string name="action_reset_schedule">Reiniciar</string>
|
||||
<string name="hint_configure_scheduled_toot">Pulsa aquí para configurar un estado programado.</string>
|
||||
<string name="post_lookup_error_format">Error al buscar el post %s</string>
|
||||
|
||||
<string name="about_powered_by_tusky">Potenciado por Tusky</string>
|
||||
</resources>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<string name="error_generic">Errorea gertatu da.</string>
|
||||
<string name="error_empty">Eremu hau ezin da hutsik egon.</string>
|
||||
<string name="error_invalid_domain">Domeinu izen okerra.</string>
|
||||
<string name="error_invalid_domain">Domeinu baliogabea sartu da</string>
|
||||
<string name="error_failed_app_registration">Akatsa saioa hasterakoan.</string>
|
||||
<string name="error_no_web_browser_found">Ez da web nabigatzailerik aurkitu.</string>
|
||||
<string name="error_authorization_unknown">Identifikatu gabeko baimentza akatsa gertatu da.</string>
|
||||
@ -27,7 +27,7 @@
|
||||
<string name="title_statuses_with_replies">Erantzunekin</string>
|
||||
<string name="title_follows">Jarraitzen</string>
|
||||
<string name="title_followers">Jarraitzaileak</string>
|
||||
<string name="title_favourites">Gogokoak</string>
|
||||
<string name="title_favourites">Gogokoenak</string>
|
||||
<string name="title_mutes">Isilduak</string>
|
||||
<string name="title_blocks">Blokeatuak</string>
|
||||
<string name="title_follow_requests">Eskakizunak</string>
|
||||
@ -99,22 +99,22 @@
|
||||
<string name="action_emoji_keyboard">Emoji teklatua</string>
|
||||
<string name="download_image">%1$s jaisten</string>
|
||||
<string name="action_copy_link">Lotura kopiatu</string>
|
||||
<string name="send_status_link_to">Tutaren URL-a partekatu…</string>
|
||||
<string name="send_status_link_to">Tutaren URLa partekatu…</string>
|
||||
<string name="send_status_content_to">Tuta partekatu…</string>
|
||||
<string name="send_media_to">Partekatu multimedia hona…</string>
|
||||
<string name="send_media_to">Partekatu media hona…</string>
|
||||
<string name="confirmation_reported">Bidalia!</string>
|
||||
<string name="confirmation_unblocked">Erabiltzailea ez dago blokeatuta iada.</string>
|
||||
<string name="confirmation_unmuted">Iada erabiltzailea ez dago mutututa.</string>
|
||||
<string name="confirmation_unblocked">Erabiltzailea desblokeatuta</string>
|
||||
<string name="confirmation_unmuted">Erabiltzailea isil gabetua</string>
|
||||
<string name="status_sent">Bidalia!</string>
|
||||
<string name="status_sent_long">Erantzuna ongi bidali da.</string>
|
||||
<string name="hint_domain">Instantzia hautatu</string>
|
||||
<string name="hint_domain">Zein instantzia\?</string>
|
||||
<string name="hint_compose">Zer duzu buruan?</string>
|
||||
<string name="hint_content_warning">Eduki abisua</string>
|
||||
<string name="hint_display_name">Izena</string>
|
||||
<string name="hint_content_warning">Eduki-abisua</string>
|
||||
<string name="hint_display_name">Agertuko den izena</string>
|
||||
<string name="hint_note">Biografia</string>
|
||||
<string name="hint_search">Bilatu…</string>
|
||||
<string name="search_no_results">Emaitzarik ez</string>
|
||||
<string name="label_quick_reply">Erantzuna…</string>
|
||||
<string name="label_quick_reply">Erantzun…</string>
|
||||
<string name="label_avatar">Irudia</string>
|
||||
<string name="label_header">Goiburua</string>
|
||||
<string name="link_whats_an_instance">Zer da instantzia?</string>
|
||||
@ -124,12 +124,12 @@
|
||||
\n\nInstantzia zure kontua dagoen gunea da, baino beste instantzietako erabiltzaileak zurean egongo balira bezala jarraitu ditzakezu.
|
||||
\n\nInformazio gehiago <a href="https://joinmastodon.org">joinmastodon.org</a> helbidean topatuko duzu.
|
||||
</string>
|
||||
<string name="dialog_title_finishing_media_upload">Multimedia igoera bukatzen</string>
|
||||
<string name="dialog_title_finishing_media_upload">Mediaren igoera bukatzen</string>
|
||||
<string name="dialog_message_uploading_media">Igotzen…</string>
|
||||
<string name="dialog_download_image">Jaitsi</string>
|
||||
<string name="dialog_message_cancel_follow_request">Lagun eskaera ezeztatu?</string>
|
||||
<string name="dialog_unfollow_warning">Kontu hau jarraitzeari utzi?</string>
|
||||
<string name="dialog_delete_toot_warning">Tuta ezabatu?</string>
|
||||
<string name="dialog_message_cancel_follow_request">Jarraipen-eskaerari uko egin\?</string>
|
||||
<string name="dialog_unfollow_warning">Kontu honi jarraitzeari utzi\?</string>
|
||||
<string name="dialog_delete_toot_warning">Tut hau ezabatu\?</string>
|
||||
<string name="visibility_public">Publikoa: Istorio publikoetan erakutsi</string>
|
||||
<string name="visibility_unlisted">Ezkutukoa: Ez erakutsi istorio publikoetan</string>
|
||||
<string name="visibility_private">Pribatua: Jarraitzaileentzat soilik ikusgai</string>
|
||||
@ -140,53 +140,53 @@
|
||||
<string name="pref_title_notification_alert_sound">Soinuarekin jakinarazi</string>
|
||||
<string name="pref_title_notification_alert_vibrate">Bibrazioarekin jakinarazi</string>
|
||||
<string name="pref_title_notification_alert_light">Led-arekin jakinarazi</string>
|
||||
<string name="pref_title_notification_filters">Noiz jakinarazi:</string>
|
||||
<string name="pref_title_notification_filters">Noiz jakinarazi</string>
|
||||
<string name="pref_title_notification_filter_mentions">Aipatzen naute</string>
|
||||
<string name="pref_title_notification_filter_follows">Jarraitzen didate</string>
|
||||
<string name="pref_title_notification_filter_reblogs">Bultzatzen naute</string>
|
||||
<string name="pref_title_notification_filter_favourites">Nire mezuak gogoko ditu</string>
|
||||
<string name="pref_title_notification_filter_favourites">Nire argitarapenak gustokoak izan dira</string>
|
||||
<string name="pref_title_appearance_settings">Interfazea</string>
|
||||
<string name="pref_title_app_theme">Gaia</string>
|
||||
<string name="pref_title_timelines">Denbora lerroak</string>
|
||||
<string name="pref_title_app_theme">Aplikazioaren gaia</string>
|
||||
<string name="pref_title_timelines">Denbora-lerroak</string>
|
||||
<string name="app_them_dark">Iluna</string>
|
||||
<string name="app_theme_light">Argia</string>
|
||||
<string name="app_theme_black">Beltza</string>
|
||||
<string name="app_theme_auto">Automatikoa</string>
|
||||
<string name="app_theme_auto">Automatikoa iluntzean</string>
|
||||
<string name="pref_title_browser_settings">Nabigatzailea</string>
|
||||
<string name="pref_title_custom_tabs">Chromeko fitxak erabili</string>
|
||||
<string name="pref_title_hide_follow_button">Tut egiteko botoia ezkutatu jaisterakoan.</string>
|
||||
<string name="pref_title_status_filter">Denbora-lerro filtroak</string>
|
||||
<string name="pref_title_custom_tabs">Chromeko fitxa pertsonalizatuak erabili</string>
|
||||
<string name="pref_title_hide_follow_button">Ezkutatu idazteko botoia mugitzean</string>
|
||||
<string name="pref_title_status_filter">Denbora-lerroko iragazkiak</string>
|
||||
<string name="pref_title_status_tabs">Fitxak</string>
|
||||
<string name="pref_title_show_boosts">Erakutsi bultzadak</string>
|
||||
<string name="pref_title_show_replies">Erakutsi erantzunak</string>
|
||||
<string name="pref_title_show_media_preview">Multimedia aurreikusi</string>
|
||||
<string name="pref_title_proxy_settings">Proxy-a</string>
|
||||
<string name="pref_title_http_proxy_settings">HTTP Proxy-a</string>
|
||||
<string name="pref_title_http_proxy_enable">HTTP Proxy-a gaitu</string>
|
||||
<string name="pref_title_http_proxy_server">HTTP Proxy-aren zerbitzaria</string>
|
||||
<string name="pref_title_http_proxy_port">HTTP Proxy-aren portua</string>
|
||||
<string name="pref_default_post_privacy">Aurrezarritako ikusgarritasuna</string>
|
||||
<string name="pref_default_media_sensitivity">Beti markatu multimedia eduki mingarri gisa</string>
|
||||
<string name="pref_publishing">Bidalketak</string>
|
||||
<string name="pref_title_show_media_preview">Jaitsi mediaren aurreikuspenak</string>
|
||||
<string name="pref_title_proxy_settings">Proxya</string>
|
||||
<string name="pref_title_http_proxy_settings">HTTP proxya</string>
|
||||
<string name="pref_title_http_proxy_enable">HTTP proxya gaitu</string>
|
||||
<string name="pref_title_http_proxy_server">HTTP proxyaren zerbitzaria</string>
|
||||
<string name="pref_title_http_proxy_port">HTTP proxyaren portua</string>
|
||||
<string name="pref_default_post_privacy">Argitarapenen aurrezarritako pribatutasuna</string>
|
||||
<string name="pref_default_media_sensitivity">Media eduki-mingarri gisa beti markatu</string>
|
||||
<string name="pref_publishing">Argitaratzeak (zerbitzariarekin sinkronizatua)</string>
|
||||
<string name="pref_failed_to_sync">Aukerak sinkronizatzean akatsa</string>
|
||||
<string name="post_privacy_public">Publikoa</string>
|
||||
<string name="post_privacy_unlisted">Ezkutukoa</string>
|
||||
<string name="post_privacy_followers_only">Pribatua</string>
|
||||
<string name="pref_status_text_size">Testuaren tamaina</string>
|
||||
<string name="status_text_size_smallest">Oso txikia</string>
|
||||
<string name="post_privacy_unlisted">Zerrendatu gabea</string>
|
||||
<string name="post_privacy_followers_only">Jarraitzaileak soilik</string>
|
||||
<string name="pref_status_text_size">Status testuaren tamaina</string>
|
||||
<string name="status_text_size_smallest">Txikiena</string>
|
||||
<string name="status_text_size_small">Txikia</string>
|
||||
<string name="status_text_size_medium">Erdikoa</string>
|
||||
<string name="status_text_size_large">Handia</string>
|
||||
<string name="status_text_size_largest">Oso handia</string>
|
||||
<string name="status_text_size_largest">Handiena</string>
|
||||
<string name="notification_mention_name">Aipamen berriak</string>
|
||||
<string name="notification_mention_descriptions">Aipamen berrien jakinarazpenak</string>
|
||||
<string name="notification_follow_name">Jarritzaile berriak</string>
|
||||
<string name="notification_follow_name">Jarraitzaile berriak</string>
|
||||
<string name="notification_follow_description">Jarraitzaile berrien jakinarazpenak</string>
|
||||
<string name="notification_boost_name">Bultzadak</string>
|
||||
<string name="notification_boost_description">Bultzatutako tuten jakinarazpenak</string>
|
||||
<string name="notification_boost_description">Bultzatutako zure tuten jakinarazpenak</string>
|
||||
<string name="notification_favourite_name">Gogokoak</string>
|
||||
<string name="notification_favourite_description">Gogokoen jakinarazpenak</string>
|
||||
<string name="notification_mention_format">%s-k aipatu zaitu</string>
|
||||
<string name="notification_favourite_description">Zure tutak gogoko bezala ezartzerakoan jakinarazpenak</string>
|
||||
<string name="notification_mention_format">%s-(e)k aipatu zaitu</string>
|
||||
<string name="notification_summary_large">%1$s, %2$s, %3$s eta beste %4$d</string>
|
||||
<string name="notification_summary_medium">%1$s, %2$s eta %3$s</string>
|
||||
<string name="notification_summary_small">%1$s eta %2$s</string>
|
||||
@ -205,12 +205,11 @@
|
||||
<string name="about_project_site"> Proiektuaren gunea:\n
|
||||
https://accelf.net/yuito
|
||||
</string>
|
||||
<string name="about_bug_feature_request_site"> Akats jakinarazpenak eta hobekuntza eskariak:\n
|
||||
https://github.com/accelforce/Yuito/issues
|
||||
</string>
|
||||
<string name="about_tusky_account">Yuito-ren profila</string>
|
||||
<string name="status_share_content">Partekatu edukia</string>
|
||||
<string name="status_share_link">Partekatu lotura</string>
|
||||
<string name="about_bug_feature_request_site">Akatsen berri-emateak eta hobekuntza-eskariak:
|
||||
\n https://github.com/accelforce/Yuito/issues</string>
|
||||
<string name="about_tusky_account">Yuitoren profila</string>
|
||||
<string name="status_share_content">Partekatu tutaren edukia</string>
|
||||
<string name="status_share_link">Partekatu tutaren lotura</string>
|
||||
<string name="status_media_images">Irudiak</string>
|
||||
<string name="status_media_video">Bideoak</string>
|
||||
<string name="state_follow_requested">Eskaera bidalita</string>
|
||||
@ -277,4 +276,196 @@
|
||||
<string name="label_remote_account">Ondorengo edukiak erabiltzailearen informazioa erdizka erakutsi dezake. Profil osoa ikusteko nabigatzailean sakatu.</string>
|
||||
<string name="unpin_action">Desainguratu</string>
|
||||
<string name="pin_action">Ainguratu</string>
|
||||
<string name="error_network">Sareko errore bat sortu da! Zure konexioa ziurta ezazu berriro, mesedez!</string>
|
||||
<string name="title_direct_messages">Mezu Zuzenak</string>
|
||||
<string name="title_tab_preferences">Kategoriak</string>
|
||||
<string name="title_statuses_pinned">Lotuta</string>
|
||||
<string name="title_domain_mutes">Ezkutuko domeinuak</string>
|
||||
<string name="title_scheduled_toot">Programatutako tutak</string>
|
||||
<string name="status_username_format">\@%s</string>
|
||||
<string name="message_empty">Kilkerrak besterik ez hemen.</string>
|
||||
<string name="action_unreblog">Bultzada kendu</string>
|
||||
<string name="action_unfavourite">Gogokoa kendu</string>
|
||||
<string name="action_edit">Editatu</string>
|
||||
<string name="action_delete_and_redraft">Ezabatu eta zirriborroa berriro egin</string>
|
||||
<string name="action_view_domain_mutes">Ezkutuko domeinuak</string>
|
||||
<string name="action_add_poll">Galdeketa gehitu</string>
|
||||
<string name="action_mute_domain">%s isilarazi</string>
|
||||
<string name="action_access_scheduled_toot">Programatutako tutak</string>
|
||||
<string name="action_schedule_toot">Tuta programatu</string>
|
||||
<string name="action_reset_schedule">Berrezarri</string>
|
||||
<string name="action_add_tab">Kategoria gehitu</string>
|
||||
<string name="action_links">Estekak</string>
|
||||
<string name="action_mentions">Aipamenak</string>
|
||||
<string name="action_open_reblogged_by">Bultzadak erakutsi</string>
|
||||
<string name="action_open_faved_by">Gogokoak erakutsi</string>
|
||||
|
||||
<string name="title_mentions_dialog">Aipamenak</string>
|
||||
<string name="title_links_dialog">Estekak</string>
|
||||
<string name="action_open_media_n">Ireki media #%d</string>
|
||||
|
||||
<string name="action_open_as">%s bezala ireki</string>
|
||||
<string name="action_share_as">... bezala partekatu</string>
|
||||
<string name="download_media">Media jaisten</string>
|
||||
<string name="downloading_media">Media jaisten</string>
|
||||
|
||||
<string name="confirmation_domain_unmuted">%s ez dago ezkutatua</string>
|
||||
|
||||
<string name="hint_configure_scheduled_toot">Sakatu hemen programatutako tuta konfiguratzeko.</string>
|
||||
<string name="dialog_redraft_toot_warning">Tut hau ezabatu eta zirriborro berria egin\?</string>
|
||||
<string name="mute_domain_warning">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.</string>
|
||||
<string name="mute_domain_warning_dialog_ok">Domeinu osoa ezkutatu</string>
|
||||
|
||||
<string name="pref_title_notification_filter_poll">Galdeketak bukatu dira</string>
|
||||
<string name="pref_title_timeline_filters">Iragazkiak</string>
|
||||
|
||||
<string name="app_theme_system">Erabili sistemaren diseinua</string>
|
||||
|
||||
<string name="pref_title_language">Hizkuntza</string>
|
||||
<string name="pref_title_bot_overlay">Botentzako erakuslea erakutsi</string>
|
||||
<string name="pref_title_animate_gif_avatars">GIF abatarrak animatu</string>
|
||||
|
||||
<string name="notification_poll_name">Galdeketak</string>
|
||||
<string name="notification_poll_description">Bukatutako galdeketen jakinarazpenak</string>
|
||||
|
||||
|
||||
<string name="about_tusky_version">Tusky %s</string>
|
||||
<string name="action_hashtags">Traolak</string>
|
||||
<string name="title_hashtags_dialog">Traolak</string>
|
||||
<string name="about_powered_by_tusky">Tusky-k sustatuta</string>
|
||||
<string name="abbreviated_hours_ago">%dh</string>
|
||||
<string name="abbreviated_minutes_ago">%dm</string>
|
||||
<string name="abbreviated_seconds_ago">%ds</string>
|
||||
|
||||
<string name="pref_title_alway_open_spoiler">Beti zabaldu edukien abisuekin markatutako tootak</string>
|
||||
<string name="pref_title_thread_filter_keywords">Elkarrizketak</string>
|
||||
<string name="filter_addition_dialog_title">Gehitu iragazkia</string>
|
||||
<string name="filter_edit_dialog_title">Editatu iragazkia</string>
|
||||
<string name="filter_dialog_remove_button">Kendu</string>
|
||||
<string name="filter_dialog_update_button">Eguneratu</string>
|
||||
<string name="filter_dialog_whole_word">Hitz osoa</string>
|
||||
<string name="filter_dialog_whole_word_description">Gako-hitza edo esaldia alfanumerikoa denean bakarrik, hitz osoarekin bat datorrenean bakarrik aplikatuko da</string>
|
||||
<string name="filter_add_description">Iragazteko esaldia</string>
|
||||
|
||||
<string name="error_create_list">Ezin izan da zerrenda sortu</string>
|
||||
<string name="error_rename_list">Ezin izan da zerrendaren izena aldatu</string>
|
||||
<string name="error_delete_list">Ezin izan da zerrenda ezabatu</string>
|
||||
<string name="action_create_list">Zerrenda sortu</string>
|
||||
<string name="action_rename_list">Zerrenda berrizendatu</string>
|
||||
<string name="action_delete_list">Ezabatu zerrenda</string>
|
||||
<string name="action_edit_list">Editatu zerrenda</string>
|
||||
<string name="hint_search_people_list">Bilatu jarraitzen dituzun pertsonak</string>
|
||||
<string name="action_add_to_list">Gehitu kontua zerrendan</string>
|
||||
<string name="action_remove_from_list">Kendu kontua zerrendatik</string>
|
||||
|
||||
<string name="caption_notoemoji">Google-ren egungo emoji multzoa</string>
|
||||
|
||||
<string name="license_cc_by_4">CC-BY 4.0</string>
|
||||
<string name="license_cc_by_sa_4">CC-BY-SA 4.0</string>
|
||||
|
||||
<plurals name="favs">
|
||||
<item quantity="one"><b>%1$s</b> Gogoko</item>
|
||||
<item quantity="other"><b>%1$s</b> Gogoko</item>
|
||||
</plurals>
|
||||
|
||||
<plurals name="reblogs">
|
||||
<item quantity="one"><b>%s</b> Bultzada</item>
|
||||
<item quantity="other"><b>%s</b> Bultzada</item>
|
||||
</plurals>
|
||||
|
||||
<string name="title_reblogged_by">Bultzatuta</string>
|
||||
<string name="title_favourited_by">Gogokoa</string>
|
||||
|
||||
<string name="conversation_1_recipients">%1$s</string>
|
||||
<string name="conversation_2_recipients">%1$s eta %2$s</string>
|
||||
<string name="conversation_more_recipients">%1$s, %2$s eta %3$d gehiago</string>
|
||||
<string name="max_tab_number_reached">geienezko %1$d fitxa iritsita</string>
|
||||
|
||||
|
||||
<string name="description_status_media">Media: %s</string>
|
||||
<string name="description_status_cw">Edukiaren abisua: %s</string>
|
||||
<string name="description_status_media_no_description_placeholder">Deskribapenik ez</string>
|
||||
<string name="description_status_reblogged">Birblogeatuta</string>
|
||||
<string name="description_status_favourited">Gogotuta</string>
|
||||
<string name="description_visiblity_public">Publiko</string>
|
||||
<string name="description_visiblity_unlisted">Zerrendagabetuta</string>
|
||||
<string name="description_visiblity_private">Jarraitzaileak</string>
|
||||
<string name="description_visiblity_direct">Zuzena</string>
|
||||
<string name="description_poll">Inkestatu aukerekin: %1$s, %2$s, %3$s, %4$s; %5$s</string>
|
||||
|
||||
<string name="hint_list_name">Zerrendaren izena</string>
|
||||
|
||||
<string name="edit_hashtag_title">Editatu traola</string>
|
||||
<string name="edit_hashtag_hint">Traola # gabe</string>
|
||||
<string name="hashtag">Traola</string>
|
||||
<string name="notifications_clear">Garbitu</string>
|
||||
<string name="notifications_apply_filter">Iragazi</string>
|
||||
<string name="filter_apply">Aplikatu</string>
|
||||
|
||||
<string name="compose_shortcut_long_label">Idatzi Toot-a</string>
|
||||
<string name="compose_shortcut_short_label">Idatzi</string>
|
||||
|
||||
<string name="notification_clear_text">Ziur zaude jakinarazpen guztiak betirako garbitu nahi dituzula\?</string>
|
||||
<string name="compose_preview_image_description">%s irudiarentzako ekintzak</string>
|
||||
|
||||
<string name="poll_info_format"> <!-- 15 boto • Ordu 1 geratzen da --> %1$s • %2$s</string>
|
||||
<plurals name="poll_info_votes">
|
||||
<item quantity="one">Boto %s</item>
|
||||
<item quantity="other">%s Boto</item>
|
||||
</plurals>
|
||||
<string name="poll_info_time_absolute">%s amaitzen da</string>
|
||||
<string name="poll_info_closed">itxita</string>
|
||||
|
||||
<string name="poll_vote">Botatu</string>
|
||||
|
||||
<string name="poll_ended_voted">Botoa eman duzun galdeketa amaitu da</string>
|
||||
<string name="poll_ended_created">Sortu duzun galdeketa amaitu da</string>
|
||||
|
||||
<plurals name="poll_timespan_days">
|
||||
<item quantity="one">Egun %d</item>
|
||||
<item quantity="other">%d egun</item>
|
||||
</plurals>
|
||||
<plurals name="poll_timespan_hours">
|
||||
<item quantity="one">Ordu %d</item>
|
||||
<item quantity="other">%d ordu</item>
|
||||
</plurals>
|
||||
<plurals name="poll_timespan_minutes">
|
||||
<item quantity="one">Minutu %d</item>
|
||||
<item quantity="other">%d minutu</item>
|
||||
</plurals>
|
||||
<plurals name="poll_timespan_seconds">
|
||||
<item quantity="one">Segundu %d</item>
|
||||
<item quantity="other">%d segundu</item>
|
||||
</plurals>
|
||||
|
||||
<string name="button_continue">Jarraitu</string>
|
||||
<string name="button_back">Itzuli</string>
|
||||
<string name="button_done">Eginda</string>
|
||||
<string name="report_sent_success">\@%s jakinarazi duzu arrakastaz</string>
|
||||
<string name="hint_additional_info">Iruzkin gehigarriak</string>
|
||||
<string name="report_remote_instance">%s-(r)i birbidali</string>
|
||||
<string name="failed_report">Txostena huts egin du</string>
|
||||
<string name="failed_fetch_statuses">Egoeren eskuratzea huts egin du</string>
|
||||
<string name="report_description_1">Txostena zure zerbitzariaren moderatzaileari bidaliko zaio. Jarraian, kontu honen zergatia salatzen duzun azalpena eman dezakezu:</string>
|
||||
<string name="report_description_remote_instance">Kontua beste zerbitzari batekoa da. Bidali txostenaren kopia anonimatua hara ere\?</string>
|
||||
<string name="title_accounts">Kontuak</string>
|
||||
<string name="failed_search">Bilaketa huts egin du</string>
|
||||
|
||||
<string name="pref_title_show_notifications_filter">Erakutsi jakinarazpenen iragazkia</string>
|
||||
|
||||
|
||||
<string name="create_poll_title">Inkesta</string>
|
||||
<string name="poll_duration_5_min">5 minutu</string>
|
||||
<string name="poll_duration_30_min">30 minutu</string>
|
||||
<string name="poll_duration_1_hour">Ordu 1</string>
|
||||
<string name="poll_duration_6_hours">6 ordu</string>
|
||||
<string name="poll_duration_1_day">Egun 1</string>
|
||||
<string name="poll_duration_3_days">3 egun</string>
|
||||
<string name="poll_duration_7_days">7 egun</string>
|
||||
<string name="add_poll_choice">Gehitu aukera</string>
|
||||
<string name="poll_allow_multiple_choices">Aukera anitzak</string>
|
||||
<string name="poll_new_choice_hint">%d. aukera</string>
|
||||
<string name="edit_poll">Editatu</string>
|
||||
<string name="post_lookup_error_format">Errorea agertu da %s mezua bilatzean</string>
|
||||
|
||||
</resources>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user