1
0
mirror of https://github.com/accelforce/Yuito synced 2025-02-13 01:50:50 +01:00

Merge remote-tracking branch 'tuskyapp/develop'

This commit is contained in:
kyori19 2020-02-23 22:23:54 +09:00
commit de8069aec9
32 changed files with 341 additions and 148 deletions

View File

@ -105,7 +105,7 @@ project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
ext.lifecycleVersion = "2.1.0"
ext.roomVersion = '2.2.3'
ext.retrofitVersion = '2.6.0'
ext.okhttpVersion = '4.2.2'
ext.okhttpVersion = '4.3.1'
ext.glideVersion = '4.10.0'
ext.daggerVersion = '2.25.3'

View File

@ -1,14 +1,10 @@
package com.keylesspalace.tusky;
import android.app.AlarmManager;
import androidx.appcompat.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@ -20,6 +16,10 @@ import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import com.keylesspalace.tusky.util.EmojiCompatFont;
import java.util.ArrayList;
@ -44,7 +44,6 @@ public class EmojiPreference extends Preference {
private boolean updated, currentNeedsUpdate;
public EmojiPreference(Context context, AttributeSet attrs) {
super(context, attrs);
@ -63,7 +62,7 @@ public class EmojiPreference extends Preference {
View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_emojicompat, null);
for(int i = 0; i < viewIds.length; i++) {
for (int i = 0; i < viewIds.length; i++) {
setupItem(view.findViewById(viewIds[i]), FONTS[i]);
}
@ -96,13 +95,13 @@ public class EmojiPreference extends Preference {
// Set actions
download.setOnClickListener((downloadButton) ->
startDownload(font, container));
startDownload(font, container));
cancel.setOnClickListener((cancelButton) ->
cancelDownload(font, container));
cancelDownload(font, container));
radio.setOnClickListener((radioButton) ->
select(font, (RadioButton) radioButton));
select(font, (RadioButton) radioButton));
container.setOnClickListener((containterView) ->
select(font,
@ -111,11 +110,11 @@ public class EmojiPreference extends Preference {
}
private void startDownload(EmojiCompatFont font, View container) {
ImageButton download = container.findViewById(R.id.emojicompat_download);
TextView caption = container.findViewById(R.id.emojicompat_caption);
ImageButton download = container.findViewById(R.id.emojicompat_download);
TextView caption = container.findViewById(R.id.emojicompat_caption);
ProgressBar progressBar = container.findViewById(R.id.emojicompat_progress);
ImageButton cancel = container.findViewById(R.id.emojicompat_download_cancel);
ImageButton cancel = container.findViewById(R.id.emojicompat_download_cancel);
// Switch to downloading style
download.setVisibility(View.GONE);
@ -136,8 +135,7 @@ public class EmojiPreference extends Preference {
progress *= progressBar.getMax();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
progressBar.setProgress((int) progress, true);
}
else {
} else {
progressBar.setProgress((int) progress);
}
}
@ -167,14 +165,15 @@ public class EmojiPreference extends Preference {
/**
* Select a font both visually and logically
* @param font The font to be selected
*
* @param font The font to be selected
* @param radio The radio button associated with it's visual item
*/
private void select(EmojiCompatFont font, RadioButton radio) {
selected = font;
// Uncheck all the other buttons
for(RadioButton other : radioButtons) {
if(other != radio) {
for (RadioButton other : radioButtons) {
if (other != radio) {
other.setChecked(false);
}
}
@ -183,31 +182,31 @@ public class EmojiPreference extends Preference {
/**
* Called when a "consistent" state is reached, i.e. it's not downloading the font
* @param font The font to be displayed
*
* @param font The font to be displayed
* @param container The ConstraintLayout containing the item
*/
private void updateItem(EmojiCompatFont font, View container) {
// Assignments
ImageButton download = container.findViewById(R.id.emojicompat_download);
TextView caption = container.findViewById(R.id.emojicompat_caption);
ImageButton download = container.findViewById(R.id.emojicompat_download);
TextView caption = container.findViewById(R.id.emojicompat_caption);
ProgressBar progress = container.findViewById(R.id.emojicompat_progress);
ImageButton cancel = container.findViewById(R.id.emojicompat_download_cancel);
ImageButton cancel = container.findViewById(R.id.emojicompat_download_cancel);
RadioButton radio = container.findViewById(R.id.emojicompat_radio);
RadioButton radio = container.findViewById(R.id.emojicompat_radio);
// There's no download going on
progress.setVisibility(View.GONE);
cancel.setVisibility(View.GONE);
caption.setVisibility(View.VISIBLE);
if(font.isDownloaded(getContext())) {
if (font.isDownloaded(getContext())) {
// Make it selectable
download.setVisibility(View.GONE);
radio.setVisibility(View.VISIBLE);
container.setClickable(true);
}
else {
} else {
// Make it downloadable
download.setVisibility(View.VISIBLE);
radio.setVisibility(View.GONE);
@ -215,14 +214,13 @@ public class EmojiPreference extends Preference {
}
// Select it if necessary
if(font == selected) {
if (font == selected) {
radio.setChecked(true);
// Update available
if (!font.isDownloaded(getContext())) {
currentNeedsUpdate = true;
}
}
else {
} else {
radio.setChecked(false);
}
}
@ -248,33 +246,33 @@ public class EmojiPreference extends Preference {
* That means, the selected font can be saved (if the user hit OK)
*/
private void onDialogOk() {
saveSelectedFont();
saveSelectedFont();
if (selected != original || updated) {
new AlertDialog.Builder(getContext())
.setTitle(R.string.restart_required)
.setMessage(R.string.restart_emoji)
.setNegativeButton(R.string.later, null)
.setPositiveButton(R.string.restart, ((dialog, which) -> {
// Restart the app
// From https://stackoverflow.com/a/17166729/5070653
Intent launchIntent = new Intent(getContext(), SplashActivity.class);
PendingIntent mPendingIntent = PendingIntent.getActivity(
getContext(),
// This is the codepoint of the party face emoji :D
0x1f973,
launchIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr =
(AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
if (mgr != null) {
mgr.set(
AlarmManager.RTC,
System.currentTimeMillis() + 100,
mPendingIntent);
}
System.exit(0);
})).show();
}
new AlertDialog.Builder(getContext())
.setTitle(R.string.restart_required)
.setMessage(R.string.restart_emoji)
.setNegativeButton(R.string.later, null)
.setPositiveButton(R.string.restart, ((dialog, which) -> {
// Restart the app
// From https://stackoverflow.com/a/17166729/5070653
Intent launchIntent = new Intent(getContext(), SplashActivity.class);
PendingIntent mPendingIntent = PendingIntent.getActivity(
getContext(),
// This is the codepoint of the party face emoji :D
0x1f973,
launchIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr =
(AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
if (mgr != null) {
mgr.set(
AlarmManager.RTC,
System.currentTimeMillis() + 100,
mPendingIntent);
}
System.exit(0);
})).show();
}
}

View File

@ -471,18 +471,21 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
return ImageLoadingHelper.decodeBlurHash(this.avatar.getContext(), blurhash);
}
private void loadImage(MediaPreviewImageView imageView, String previewUrl, MetaData meta,
private void loadImage(MediaPreviewImageView imageView,
@Nullable String previewUrl,
@Nullable MetaData meta,
@Nullable String blurhash) {
Drawable placeholder = blurhash != null ? decodeBlurHash(blurhash) : mediaPreviewUnloaded;
if (TextUtils.isEmpty(previewUrl)) {
if (blurhash != null) {
imageView.setImageDrawable(decodeBlurHash(blurhash));
} else {
Glide.with(imageView)
.load(placeholder)
.centerInside()
.into(imageView);
}
imageView.removeFocalPoint();
Glide.with(imageView)
.load(placeholder)
.centerInside()
.into(imageView);
} else {
Focus focus = meta != null ? meta.getFocus() : null;
@ -541,18 +544,12 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
imageView.setContentDescription(description);
}
if (showingContent) {
loadImage(imageView, previewUrl, attachment.getMeta(), attachment.getBlurhash());
} else {
imageView.setFocalPoint(null);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
if (useBlurhash && attachment.getBlurhash() != null) {
BitmapDrawable blurhashBitmap = decodeBlurHash(attachment.getBlurhash());
imageView.setImageDrawable(blurhashBitmap);
} else {
imageView.setImageDrawable(mediaPreviewUnloaded);
}
}
loadImage(
imageView,
showingContent ? previewUrl : null,
attachment.getMeta(),
useBlurhash ? attachment.getBlurhash() : null
);
final Attachment.Type type = attachment.getType();
if (showingContent && (type == Attachment.Type.VIDEO || type == Attachment.Type.GIFV)) {

View File

@ -483,10 +483,11 @@ class ComposeActivity : BaseActivity(),
// If you select "backward" in an editable, you get SelectionStart > SelectionEnd
val start = composeEditField.selectionStart.coerceAtMost(composeEditField.selectionEnd)
val end = composeEditField.selectionStart.coerceAtLeast(composeEditField.selectionEnd)
val textToInsert = if (
composeEditField.text.isNotEmpty()
&& !composeEditField.text[start - 1].isWhitespace()
) " $text" else text
val textToInsert = if (start > 0 && !composeEditField.text[start - 1].isWhitespace()) {
" $text"
} else {
text
}
composeEditField.text.replace(start, end, textToInsert)
// Set the cursor after the inserted text
@ -836,7 +837,7 @@ class ComposeActivity : BaseActivity(),
viewModel.sendStatus(contentText, spoilerText).observe(this, Observer {
finishingUploadDialog?.dismiss()
finishWithoutSlideOutAnimation()
deleteDraftAndFinish()
})
} else {

View File

@ -97,12 +97,12 @@ class SearchDataSource<T>(
.subscribe(
{ data ->
// Working around Mastodon bug where exact match is returned no matter
// which offset is requested (so if we seach for a full username, it's
// which offset is requested (so if we search for a full username, it's
// infinite)
// see https://github.com/tootsuite/mastodon/issues/11365
val res = if (data.accounts.size == 1
&& data.accounts[0].username
.equals(searchRequest, ignoreCase = true)) {
// see https://github.com/tootsuite/mastodon/issues/13083
val res = if ((data.accounts.size == 1 && data.accounts[0].username.equals(searchRequest, ignoreCase = true))
|| (data.statuses.size == 1 && data.statuses[0].url.equals(searchRequest))) {
listOf()
} else {
parser(data)

View File

@ -428,16 +428,19 @@ interface MastodonApi {
@Query("limit") limit: Int
): Single<List<Account>>
@DELETE("api/v1/lists/{listId}/accounts")
@FormUrlEncoded
// @DELETE doesn't support fields
@HTTP(method = "DELETE", path = "api/v1/lists/{listId}/accounts", hasBody = true)
fun deleteAccountFromList(
@Path("listId") listId: String,
@Query("account_ids[]") accountIds: List<String>
@Field("account_ids[]") accountIds: List<String>
): Completable
@FormUrlEncoded
@POST("api/v1/lists/{listId}/accounts")
fun addCountToList(
@Path("listId") listId: String,
@Query("account_ids[]") accountIds: List<String>
@Field("account_ids[]") accountIds: List<String>
): Completable
@GET("/api/v1/conversations")

View File

@ -8,6 +8,7 @@ import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.keylesspalace.tusky.R;
@ -27,6 +28,7 @@ import de.c1710.filemojicompat.FileEmojiCompatConfig;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
@ -81,7 +83,7 @@ public class EmojiCompatFont {
R.drawable.ic_notoemoji,
"https://tusky.app/hosted/emoji/NotoEmojiCompat.ttf",
"11.0.0"
);
);
/**
* This array stores all available EmojiCompat fonts.
@ -109,14 +111,14 @@ public class EmojiCompatFont {
/**
* Returns the Emoji font associated with this ID
*
* @param id the ID of this font
* @return the corresponding font. Will default to SYSTEM_DEFAULT if not in range.
*/
public static EmojiCompatFont byId(int id) {
if(id >= 0 && id < FONTS.length) {
if (id >= 0 && id < FONTS.length) {
return FONTS[id];
}
else {
} else {
return SYSTEM_DEFAULT;
}
}
@ -143,7 +145,7 @@ public class EmojiCompatFont {
}
public Drawable getThumb(Context context) {
return context.getResources().getDrawable(img);
return ContextCompat.getDrawable(context, img);
}
public String getVersion() {
@ -157,15 +159,15 @@ public class EmojiCompatFont {
/**
* This method will return the actual font file (regardless of its existence) for
* the current version (not necessarily the latest!).
*
* @return The font (TTF) file or null if called on SYSTEM_FONT
*/
@Nullable
private File getFont(Context context) {
if(this != SYSTEM_DEFAULT) {
if (this != SYSTEM_DEFAULT) {
File directory = new File(context.getExternalFilesDir(null), DIRECTORY);
return new File(directory, this.getName() + this.getVersion() + ".ttf");
}
else {
} else {
return null;
}
}
@ -185,6 +187,7 @@ public class EmojiCompatFont {
/**
* Checks whether there is already a font version that satisfies the current version, i.e. it
* has a higher or equal version code.
*
* @param context The Context
* @return Whether there is a font file with a higher or equal version code to the current
*/
@ -199,10 +202,11 @@ public class EmojiCompatFont {
/**
* Downloads the TTF file for this font
*
* @param listeners The listeners which will be notified when the download has been finished
*/
public void downloadFont(Context context, Downloader.EmojiDownloadListener... listeners) {
if(this != SYSTEM_DEFAULT) {
if (this != SYSTEM_DEFAULT) {
// Additionally run a cleanup process after the download has been successful.
Downloader.EmojiDownloadListener cleanup = font -> deleteOldVersions(context);
@ -216,9 +220,8 @@ public class EmojiCompatFont {
this,
allListeners.toArray(allListenersA))
.execute(getFont(context));
}
else {
for(Downloader.EmojiDownloadListener listener: listeners) {
} else {
for (Downloader.EmojiDownloadListener listener : listeners) {
// The system emoji font is always downloaded...
listener.onDownloaded(this);
}
@ -227,6 +230,7 @@ public class EmojiCompatFont {
/**
* Deletes any older version of a font
*
* @param context The current Context
*/
private void deleteOldVersions(Context context) {
@ -236,11 +240,11 @@ public class EmojiCompatFont {
Log.d(TAG, String.format("deleteOldVersions: Found %d other font files", existingFontFiles.size()));
for (Pair<File, int[]> fileExists : existingFontFiles) {
if (compareVersions(fileExists.second, getVersionCode()) < 0) {
File file = fileExists.first;
// Uses side effects!
Log.d(TAG, String.format("Deleted %s successfully: %s", file.getAbsolutePath(),
file.delete()));
}
File file = fileExists.first;
// Uses side effects!
Log.d(TAG, String.format("Deleted %s successfully: %s", file.getAbsolutePath(),
file.delete()));
}
}
}
@ -250,6 +254,7 @@ public class EmojiCompatFont {
/**
* Loads all font files that are inside the files directory into an ArrayList with the information
* on whether they are older than the currently available version or not.
*
* @param context The Context
*/
private void loadExistingFontFiles(Context context) {
@ -274,7 +279,7 @@ public class EmojiCompatFont {
this.existingFontFiles = new ArrayList<>(existingFontFiles.length);
for(File file : existingFontFiles) {
for (File file : existingFontFiles) {
Matcher matcher = fontRegex.matcher(file.getName());
if (matcher.matches()) {
String version = matcher.group(1);
@ -294,6 +299,7 @@ public class EmojiCompatFont {
/**
* Returns the current or latest version of this font file (if there is any)
*
* @param context The Context
* @return The file for this font with the current or (if not existent) highest version code or null if there is no file for this font.
*/
@ -380,7 +386,7 @@ public class EmojiCompatFont {
* Stops downloading the font. If no one started a font download, nothing happens.
*/
public void cancelDownload() {
if(fontDownloader != null) {
if (fontDownloader != null) {
fontDownloader.cancel(false);
fontDownloader = null;
}
@ -407,7 +413,7 @@ public class EmojiCompatFont {
}
@Override
protected File doInBackground(File... files){
protected File doInBackground(File... files) {
// Only download to one file...
File downloadFile = files[0];
try {
@ -428,7 +434,7 @@ public class EmojiCompatFont {
// Download!
if (response.body() != null
&& response.isSuccessful()
&& (size = response.body().contentLength()) > 0) {
&& (size = networkResponseLength(response)) > 0) {
float progress = 0;
source = response.body().source();
try {
@ -448,14 +454,13 @@ public class EmojiCompatFont {
Log.e(TAG, "Status code: " + response.code());
failed = true;
}
}
finally {
if(source != null) {
} finally {
if (source != null) {
source.close();
}
sink.close();
// This 'if' uses side effects to delete the File.
if(isCancelled() && !downloadFile.delete()) {
if (isCancelled() && !downloadFile.delete()) {
Log.e(TAG, "Could not delete file " + downloadFile);
}
}
@ -468,28 +473,27 @@ public class EmojiCompatFont {
@Override
public void onProgressUpdate(Float... progress) {
for(EmojiDownloadListener listener: listeners) {
for (EmojiDownloadListener listener : listeners) {
listener.onProgress(progress[0]);
}
}
@Override
public void onPostExecute(File downloadedFile) {
if(!failed && downloadedFile.exists()) {
if (!failed && downloadedFile.exists()) {
for (EmojiDownloadListener listener : listeners) {
listener.onDownloaded(font);
}
}
else {
} else {
fail(downloadedFile);
}
}
private void fail(File failedFile) {
if(failedFile.exists() && !failedFile.delete()) {
if (failedFile.exists() && !failedFile.delete()) {
Log.e(TAG, "Could not delete file " + failedFile);
}
for(EmojiDownloadListener listener : listeners) {
for (EmojiDownloadListener listener : listeners) {
listener.onFailed();
}
}
@ -500,11 +504,13 @@ public class EmojiCompatFont {
public interface EmojiDownloadListener {
/**
* Called after successfully finishing a download.
*
* @param font The font related to this download. This will help identifying the download
*/
void onDownloaded(EmojiCompatFont font);
// TODO: Add functionality
/**
* Called when something went wrong with the download.
* This one won't be called when the download has been cancelled though.
@ -515,12 +521,39 @@ public class EmojiCompatFont {
/**
* Called whenever the progress changed
*
* @param Progress A value between 0 and 1 representing the current progress
*/
default void onProgress(float Progress) {
// ARE WE THERE YET?
}
}
/**
* This method is needed because when transparent compression is used OkHttp reports
* {@link ResponseBody#contentLength()} as -1. We try to get the header which server sent
* us manually here.
*
* @see <a href="https://github.com/square/okhttp/issues/259">OkHttp issue 259</a>
*/
private long networkResponseLength(Response response) {
Response networkResponse = response.networkResponse();
if (networkResponse == null) {
// In case it's a fully cached response
ResponseBody body = response.body();
return body == null ? -1 : body.contentLength();
}
String header = networkResponse.header("Content-Length");
if (header == null) {
return -1;
}
try {
return Integer.parseInt(header);
} catch (NumberFormatException e) {
return -1;
}
}
}
@Override

View File

@ -2,5 +2,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size android:width="4dp" />
<solid android:color="?attr/colorBackgroundAccent" />
<solid android:color="?attr/dividerColor" />
</shape>

View File

@ -4,6 +4,6 @@
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="?android:attr/textColorSecondary"
android:fillColor="?attr/iconColor"
android:pathData="M12,17.5C14.33,17.5 16.3,16.04 17.11,14H6.89C7.69,16.04 9.67,17.5 12,17.5M8.5,11A1.5,1.5 0 0,0 10,9.5A1.5,1.5 0 0,0 8.5,8A1.5,1.5 0 0,0 7,9.5A1.5,1.5 0 0,0 8.5,11M15.5,11A1.5,1.5 0 0,0 17,9.5A1.5,1.5 0 0,0 15.5,8A1.5,1.5 0 0,0 14,9.5A1.5,1.5 0 0,0 15.5,11M12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20M12,2C6.47,2 2,6.5 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" />
</vector>

View File

@ -29,7 +29,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/searchView" />
<com.keylesspalace.tusky.view.BackgroundMessageView
android:id="@+id/messageView"
android:layout_width="wrap_content"
@ -43,16 +42,15 @@
tools:src="@drawable/elephant_error"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/accountsSearchRecycler"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:background="?android:attr/windowBackground"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/searchView" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -257,10 +257,10 @@
<string name="action_lists">Listen</string>
<string name="title_lists">Listen</string>
<string name="title_list_timeline">Liste</string>
<string name="action_create_list">Eine Liste erstellen</string>
<string name="action_rename_list">Eine Liste umbenennen</string>
<string name="action_delete_list">Eine Liste löschen</string>
<string name="action_edit_list">Eine Liste bearbeiten</string>
<string name="action_create_list">Liste erstellen</string>
<string name="action_rename_list">Liste umbenennen</string>
<string name="action_delete_list">Liste löschen</string>
<string name="action_edit_list">Liste bearbeiten</string>
<string name="action_add_to_list">Ein Konto zu einer Liste hinzufügen</string>
<string name="compose_active_account_description">verfassen mit %1$s</string>
<string name="error_failed_set_caption">Fehler beim Speichern der Beschreibung</string>
@ -450,14 +450,13 @@
<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="abbreviated_in_years">Dies sind Zeitstempel für Status. Beispiele: \"16s\" oder \"2t\".</string>
<string name="error_audio_upload_size">Audiodateien müssen kleiner als 40MB sein.</string>
<string name="title_bookmarks">Lesezeichen</string>
<string name="action_bookmark">Lesezeichen</string>
<string name="action_view_bookmarks">Lesezeichen</string>
<string name="gradient_for_media">Bunten Farbverlauf für versteckte Medien anzeigen</string>
<string name="about_powered_by_tusky">Angetrieben durch Tusky</string>
<string name="about_powered_by_tusky">Powered by Tusky</string>
<plurals name="reblogs">
<item quantity="one"><b>%s</b> Boost</item>
<item quantity="other"><b>%s</b> Boosts</item>

View File

@ -467,10 +467,16 @@
<string name="post_lookup_error_format">Error al buscar el post %s</string>
<string name="about_powered_by_tusky">Potenciado por Tusky</string>
<string name="title_bookmarks">Favoritos</string>
<string name="title_bookmarks">Marcadores</string>
<string name="action_bookmark">Favorito</string>
<string name="action_view_bookmarks">Favoritos</string>
<string name="action_view_bookmarks">Marcadores</string>
<string name="description_status_bookmarked">Marcado como favorito</string>
<string name="select_list_title">Seleccionar lista</string>
<string name="list">Lista</string>
</resources>
<string name="error_audio_upload_size">Los ficheros de audio deben ser menores de 40MB.</string>
<string name="gradient_for_media">Mostrar degradados coloridos para el contenido multimedia oculto.</string>
<string name="no_saved_status">No tienes ningún borrador.</string>
<string name="no_scheduled_status">No tienes ningún estado programado.</string>
</resources>

View File

@ -23,7 +23,7 @@
<string name="title_public_local">محلی</string>
<string name="title_public_federated">همگانی</string>
<string name="title_view_thread">بوق</string>
<string name="title_statuses">فرسته‌ها</string>
<string name="title_statuses">بوق</string>
<string name="title_statuses_with_replies">با پاسخ‌</string>
<string name="title_follows">پی می‌گیرد</string>
<string name="title_followers">پی‌گیر</string>
@ -34,7 +34,7 @@
<string name="title_edit_profile">ویرایش نمایه‌تان</string>
<string name="title_saved_toot">پیش‌نویس‌ها</string>
<string name="title_licenses">پروانه‌ها</string>
<string name="status_boosted_format">%s تقویت شد</string>
<string name="status_boosted_format">%s تقویت کرد</string>
<string name="status_sensitive_media_title">محتوای حسّاس</string>
<string name="status_media_hidden_title">رسانهٔ پنهان</string>
<string name="status_sensitive_media_directions">کلیک برای نمایش</string>
@ -54,7 +54,7 @@
<string name="action_favourite">پسند</string>
<string name="action_more">بیش‌تر</string>
<string name="action_compose">ایجاد</string>
<string name="action_login">ورود با ماستدون</string>
<string name="action_login">ورود با ماستودون</string>
<string name="action_logout">خروج</string>
<string name="action_logout_confirm">مطمئنید می‌خواهید از حساب %1s خارج شوید؟</string>
<string name="action_follow">پیگیری</string>
@ -225,7 +225,7 @@
<string name="replying_to">در حال پاسخ به @%s</string>
<string name="load_more_placeholder_text">بارگیری بیش‌تر</string>
<string name="add_account_name">افزودن حساب</string>
<string name="add_account_description">افزودن حساب ماستدون جدید</string>
<string name="add_account_description">افزودن حساب جدید ماستودون</string>
<string name="action_lists">فهرست‌ها</string>
<string name="title_lists">فهرست‌ها</string>
<string name="title_list_timeline">خط زمانی فهرست</string>
@ -257,7 +257,7 @@
<string name="restart">شروع دوباره</string>
<string name="caption_systememoji">مجموعهٔ اموجی پیش‌گزیدهٔ افزاره‌تان</string>
<string name="caption_blobmoji">اموجی‌های اندروید ۴.۴ تا ۷.۱</string>
<string name="caption_twemoji">مجموعهٔ اموجی استاندارد ماستدون</string>
<string name="caption_twemoji">مجموعهٔ اموجی استاندارد ماستودون</string>
<string name="download_failed">شکست در بارگیری</string>
<string name="profile_badge_bot_text">بات</string>
<string name="account_moved_description">%1$s منتقل شد به:</string>

View File

@ -8,8 +8,8 @@
<string name="action_edit_profile">Ẓreg amaγnu</string>
<string name="action_search">Nadi</string>
<string name="about_title_activity">Γef</string>
<string name="action_lists">Tibdarin</string>
<string name="title_lists">Tibdarin</string>
<string name="action_lists">Umuγen</string>
<string name="title_lists">Umuγen</string>
<string name="error_compose_character_limit">Tijewwiqt-ik aṭas i γuzzifet!</string>
<string name="title_home">Agejdan</string>
<string name="title_tab_preferences">Iccaren</string>
@ -49,7 +49,7 @@
<item quantity="other"><b>%1$s</b> n ismenyifen</item>
</plurals>
<string name="no_saved_status">Ur teɛiḍ ara irewwayen.</string>
<string name="no_saved_status">Ur tesɛiḍ ara irewwayen.</string>
<string name="error_generic">Tella-d tucḍa.</string>
<string name="title_notifications">Tilγa</string>
<string name="link_whats_an_instance">D acu i ttummant\?</string>
@ -124,4 +124,116 @@
<string name="compose_shortcut_short_label">Azen</string>
<string name="edit_poll">Ẓreg</string>
<string name="title_statuses_pinned">Yettwanṭḍen</string>
<string name="action_add_media">Rnu amidya</string>
<string name="action_add_poll">Rnu assenqed</string>
<string name="action_photo_take">Ṭef tugna</string>
<string name="action_toggle_visibility">Timeẓriwt n tijewwaqt</string>
<string name="action_schedule_toot">Sγiwes tijewwaqt-a</string>
<string name="status_share_content">Bḍu agbur n tijewwiqt-a</string>
<string name="status_share_link">Bḍu aseγwen γer tijewwiqt</string>
<string name="filter_addition_dialog_title">Rnu amsizdeg</string>
<string name="filter_edit_dialog_title">Ẓreg amsizdeg</string>
<string name="action_create_list">Snulfu-d umuγ</string>
<string name="action_rename_list">Snifel isem n wumuγ</string>
<string name="action_delete_list">Kkes umuγ-a</string>
<string name="action_edit_list">Ẓreg umuγ-a</string>
<string name="action_add_to_list">Rnu yiwen umiḍan γer tabdert</string>
<string name="action_remove_from_list">Kkes amiḍan seg wumuγ</string>
<string name="profile_metadata_add">Rnu isefka</string>
<string name="hint_list_name">Isem n wumuγ</string>
<string name="select_list_title">Fren tabdart</string>
<string name="list">Umuγ</string>
<string name="notifications_apply_filter">Sizdeg</string>
<string name="title_accounts">Imiḍanen</string>
<string name="add_poll_choice">Rnu yiwen wefran</string>
<string name="report_username_format">Ccetki γef @%s</string>
<string name="action_report">Ccetki</string>
<string name="action_reject">Ggami</string>
<string name="download_image">Yessidired %1$s</string>
<string name="send_media_to">Bḍu tugna s…</string>
<string name="login_connection">itteqqen…</string>
<string name="dialog_message_uploading_media">Issalay…</string>
<string name="pref_title_notification_filter_poll">fukken kran n wadγaren</string>
<string name="pref_title_timeline_filters">Imzizdigen</string>
<string name="app_theme_auto">Akken yella yiṭij</string>
<string name="pref_title_browser_settings">Iminig</string>
<string name="pref_title_show_replies">Sken-ed tiririyin</string>
<string name="pref_title_http_proxy_settings">Apṛuksi HTTP</string>
<string name="pref_title_http_proxy_server">Tansa n upṛuksi HTTP</string>
<string name="notification_follow_name">Imeḍfaṛen imaynuten</string>
<string name="notification_poll_name">Adγaren</string>
<string name="notification_mention_format">Yuder-ik-id %s</string>
<string name="description_account_locked">Yettwargel umiḍan</string>
<string name="abbreviated_years_ago">%dis aya</string>
<string name="abbreviated_days_ago">%dus aya</string>
<string name="replying_to">Tettaraḍ-as i @%s</string>
<string name="load_more_placeholder_text">awid ugar</string>
<string name="pref_title_thread_filter_keywords">Idewenniyen</string>
<string name="lock_account_label">Rgel amiḍan</string>
<string name="performing_lookup_title">Yettnadi…</string>
<string name="restart">Ales tanekra</string>
<string name="download_failed">Tuccḍa n usider</string>
<string name="account_moved_description">Igujj %1$s γer:</string>
<string name="unpin_action">Kkes asenṭeḍ</string>
<string name="conversation_1_recipients">%1$s</string>
<string name="conversation_2_recipients">%1$s akked %2$s</string>
<string name="conversation_more_recipients">%1$s, %2$s akked %3$d nniḍen</string>
<string name="compose_shortcut_long_label">Aru tijewwiqt</string>
<string name="poll_info_format"> <!-- 15 n wadγaren • 1 n wesrag id yeqqimen --> %1$s • %2$s</string>
<plurals name="poll_info_votes">
<item quantity="one">%s wedγar</item>
<item quantity="other">%s n yedγaren</item>
</plurals>
<string name="poll_info_time_relative">%s id yugran</string>
<string name="poll_info_time_absolute">ad ifak deg %s</string>
<string name="poll_info_closed">ifuk</string>
<string name="poll_vote">Dγer</string>
<string name="poll_ended_voted">Ifuk, tura kan, yiwen wedγar t tteki-iḍ degs</string>
<string name="poll_ended_created">Ifukk yiwen wedγar id snulfaḍ</string>
<plurals name="poll_timespan_days">
<item quantity="one">%d n wass</item>
<item quantity="other">%d n wussan</item>
</plurals>
<plurals name="poll_timespan_hours">
<item quantity="one">%d wesrag</item>
<item quantity="other">%d n yisragen</item>
</plurals>
<plurals name="poll_timespan_minutes">
<item quantity="one">%d n tasdidt</item>
<item quantity="other">%d n tesdidin</item>
</plurals>
<string name="button_continue">Kemmel</string>
<string name="button_back">Uγal</string>
<string name="failed_report">Tella-d tuccḍa deg ccetki</string>
<string name="failed_search">Tucḍa n unadi</string>
<string name="create_poll_title">Assenqed</string>
<string name="poll_duration_5_min">5 n tasditin</string>
<string name="poll_duration_30_min">30 n tasditin</string>
<string name="poll_duration_1_hour">1 n wesrag</string>
<string name="poll_duration_6_hours">6 n wesragen</string>
<string name="poll_duration_1_day">1 n wass</string>
<string name="poll_duration_3_days">3 n wussan</string>
<string name="poll_duration_7_days">7 n wussan</string>
<string name="poll_new_choice_hint">Tafrant %d</string>
<string name="title_follows">Ig ṭafaṛ</string>
<string name="title_followers">Imeḍfaṛen</string>
<string name="hint_search_people_list">Nadi γef medden i teṭafareḍ</string>
<string name="description_visiblity_private">Imeḍfaṛen</string>
</resources>

View File

@ -492,4 +492,10 @@
<string name="description_status_bookmarked">Dodane do zakładek</string>
<string name="select_list_title">Wybierz listę</string>
<string name="list">Lista</string>
</resources>
<string name="error_audio_upload_size">Pliki audio muszą być mniejsze niż 40MB.</string>
<string name="gradient_for_media">Pokaż kolorowe gradienty dla ukrytych mediów</string>
<string name="no_saved_status">Nie masz żadnych szkiców.</string>
<string name="no_scheduled_status">Nie masz żadnych zaplanowanych wpisów.</string>
</resources>

View File

@ -484,4 +484,6 @@
<string name="no_scheduled_status">Sem toots agendados.</string>
</resources>
<string name="error_audio_upload_size">Áudios devem ser menores que 40MB.</string>
<string name="no_saved_status">Sem rascunhos.</string>
</resources>

View File

@ -91,8 +91,6 @@
<string name="title_view_thread">Toot</string>
<string name="notification_favourite_format">%s si obľúbil/a váš toot</string>
<string name="action_reblog"></string>
<string name="action_unreblog"></string>
<string name="action_send">TOOT</string>
<string name="action_send_public">TOOT!</string>
<string name="action_toggle_visibility">Viditeľnosť tootu</string>
@ -106,4 +104,12 @@
<string name="send_toot_notification_saved_content">Kópia vášho tootu bola uložená do konceptov</string>
<string name="action_open_toot">Otvoriť toot</string>
<string name="compose_shortcut_long_label">Napísať toot</string>
<string name="title_scheduled_toot">Plánované tooty</string>
<string name="action_access_scheduled_toot">Plánované tooty</string>
<string name="label_avatar">Avatar</string>
<string name="action_remove">Odstrániť</string>
<string name="lock_account_label">Uzamknúť účet</string>
<string name="compose_save_draft">Uložiť koncept\?</string>
<string name="send_toot_notification_channel_name">Odosielanie tootov</string>
<string name="send_toot_notification_cancel_title">Odosielanie bolo zrušené</string>
</resources>

View File

@ -118,7 +118,7 @@
<string name="action_open_media_n">Öppna media #%d</string>
<string name="download_image">Laddar ned %1$s</string>
<string name="action_copy_link">Kopiera länk</string>
<string name="action_open_as">Öppen som %s</string>
<string name="action_open_as">Öppna med %s</string>
<string name="action_share_as">Dela som …</string>
<string name="send_status_link_to">Dela toot-URL till…</string>
<string name="send_status_content_to">Dela toot till…</string>

View File

@ -21,7 +21,7 @@
<color name="tusky_grey_70">#9baec8</color>
<color name="tusky_grey_80">#b9c8d8</color>
<color name="tusky_grey_90">#d9e1e8</color>
<color name="tusky_grey_95">#e9edf2</color>
<color name="tusky_grey_95">#ebeff4</color>
<color name="transparent_tusky_blue">#8c2b90d9</color>

View File

@ -97,7 +97,7 @@
<style name="TuskyDialogFragmentStyle" parent="@style/ThemeOverlay.MaterialComponents.Dialog">
<item name="dialogCornerRadius">8dp</item>
<item name="android:backgroundTint">?attr/windowBackgroundColor</item>
<item name="android:backgroundTint">@color/colorBackground</item>
</style>
<style name="TuskyTabAppearance" parent="Widget.MaterialComponents.TabLayout">

View File

@ -0,0 +1,3 @@
Tusky v9.1
يكفل هذا التحديث التوافق مع ماستدون 3 ويحسن الأداء والاستقرار.

View File

@ -0,0 +1,8 @@
Tusky v10.0
- Du kannst jetzt Lesezeichen hinzufügen und ansehen
- Du kannst jetzt Posts vorausplanen. Achtung, der geplante Zeitpunkt muss mindestens 5 Minuten in der Zukunft liegen!
- Du kannst jetzt Listen auf dem Hauptbildschirm anzeigen.
- Du kannst jetzt Audio-Anhänge versenden.
Und viele andere Verbesserungen und Fehlerkorrekturen!

View File

@ -0,0 +1,8 @@
Tusky v10.0
- You can now bookmark statuses & list your bookmarks in Tusky.
- You can now schedule toots with Tusky. Note that the time you select has to be at least 5 minutes in the future.
- You can now add lists to the main screen.
- You can now post audio attachments with Tusky.
And a lot of other small improvements and bug fixes!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 KiB

After

Width:  |  Height:  |  Size: 998 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 817 KiB

After

Width:  |  Height:  |  Size: 625 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 KiB

After

Width:  |  Height:  |  Size: 964 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 KiB

After

Width:  |  Height:  |  Size: 317 KiB

View File

@ -0,0 +1,9 @@
Tusky v9.0
- Teraz z Tusky môžete vytvárať ankety
- Vylepšené vyhľadávanie
- Nová možnost v nastaveniach účtu umožňuje automaticky rozbaľovať varovania obsahu
- Avatary v navigačnom menu majú odteraz zaokrúhlené rohy
- Odteraz je možné nahlásiť používateľa aj keď ešte nenapísali žiadny príspevok
- Tusky bude odteraz odmietať nešifrované spojenie na Androidu 6+
- Veľa ďalších malých vylepšení a opráv

View File

@ -0,0 +1,3 @@
Tusky v9.1
Toto vydanie zaisťuje kompatibilitu s Mastodon 3 a vylepšuje výkon a stabilitu.

View File

@ -0,0 +1 @@
Viacúčtový klient pre sociálnu sieť Mastodon