Compare commits

...

75 Commits

Author SHA1 Message Date
Grishka
a9ef1f9d47 Someone else's code throwing too many exceptions again, yay 2024-07-10 02:48:33 +03:00
Grishka
0182763b58 Fixes 2024-07-10 01:01:31 +03:00
Grishka
761cadbcc7 Prepare new release 2024-07-10 00:43:46 +03:00
Grishka
ff7b6e4564 Merge branch 'donations' 2024-07-10 00:39:43 +03:00
Grishka
db84317f7f Merge branch 'master' into donations
# Conflicts:
#	mastodon/build.gradle
2024-07-03 01:30:43 +03:00
Grishka
72df72228f Merge branch 'l10n_master' 2024-07-03 01:18:18 +03:00
Grishka
3e26bd2f52 Crash fixes 2024-07-03 01:17:47 +03:00
Grishka
f241d74e27 Bump version 2024-07-01 01:18:03 +03:00
Grishka
ff0f3b414b Rename method 2024-07-01 01:13:32 +03:00
Grishka
188da6dbf7 Merge branch 'master' into donations
# Conflicts:
#	mastodon/build.gradle
2024-07-01 00:57:35 +03:00
Grishka
f9fd62db09 Fix for a crash that resulted from a previous crash fix 2024-07-01 00:56:39 +03:00
Eugen Rochko
4795a5ff6e New translations strings.xml (Lithuanian) 2024-06-30 23:09:16 +02:00
Eugen Rochko
4da52e4797 New translations strings.xml (Ukrainian) 2024-06-30 16:42:53 +02:00
Eugen Rochko
46bc0ccbeb New translations strings.xml (Ukrainian) 2024-06-30 15:46:35 +02:00
Grishka
75f1caf022 Bump version 2024-06-29 22:13:18 +03:00
Grishka
6f6d2e1e08 Merge branch 'l10n_master' 2024-06-29 22:12:21 +03:00
Grishka
027b873f13 Merge branch 'master' into donations 2024-06-29 09:13:29 +03:00
Grishka
482b7d5e7d Don't show "this post is old" for own posts 2024-06-29 09:13:05 +03:00
Grishka
1e729d97a0 Crash fixes 2024-06-29 09:11:03 +03:00
Eugen Rochko
357e348681 New translations strings.xml (Hungarian) 2024-06-27 08:23:50 +02:00
Grishka
65c1b4def0 oops 2024-06-26 20:27:10 +03:00
Grishka
461eac8932 Support multiple authors in link cards (mastodon/mastodon#30846) 2024-06-26 20:24:32 +03:00
Grishka
9a679de9c9 Fix donations and update AppCenter SDK 2024-06-25 17:18:40 +03:00
Eugen Rochko
12d4ec2129 New translations strings.xml (Armenian) 2024-06-25 12:22:04 +02:00
Eugen Rochko
26f9737e5e New translations strings.xml (Armenian) 2024-06-25 10:47:07 +02:00
Eugen Rochko
771740ca93 New translations strings.xml (Persian) 2024-06-23 14:55:50 +02:00
Eugen Rochko
ed070118d6 New translations strings.xml (Portuguese, Brazilian) 2024-06-23 06:51:10 +02:00
Grishka
88c0985908 Merge branch 'master' into donations
# Conflicts:
#	mastodon/build.gradle
2024-06-23 04:57:02 +03:00
Grishka
e7094beab9 More crash fixes 2024-06-23 04:54:43 +03:00
Grishka
501a2715be Crash fixes
fixes #854
2024-06-23 04:45:56 +03:00
Eugen Rochko
bc2380dfb1 New translations full_description.txt (Interlingua) 2024-06-22 23:14:10 +02:00
Eugen Rochko
4b584af0a9 New translations full_description.txt (French) 2024-06-22 23:14:10 +02:00
Eugen Rochko
4bc1083939 New translations strings.xml (Interlingua) 2024-06-22 23:14:09 +02:00
Eugen Rochko
b34b5032ee New translations strings.xml (Interlingua) 2024-06-22 22:17:44 +02:00
Eugen Rochko
d10b70cc62 New translations strings.xml (Interlingua) 2024-06-22 20:47:15 +02:00
Eugen Rochko
a8ba45c14b New translations strings.xml (Dutch) 2024-06-22 20:47:14 +02:00
Grishka
a50a2446a7 Update targetSDK to 34 2024-06-22 02:48:37 +03:00
Grishka
4e2e3fb4e2 Add donation options to settings 2024-06-22 02:33:06 +03:00
Eugen Rochko
9d34f0896f New translations strings.xml (Dutch) 2024-06-21 04:46:43 +02:00
Eugen Rochko
e492aca885 New translations strings.xml (Interlingua) 2024-06-21 03:42:43 +02:00
Eugen Rochko
12208b849a New translations strings.xml (Interlingua) 2024-06-21 02:45:44 +02:00
Eugen Rochko
7f2af61244 New translations strings.xml (Interlingua) 2024-06-21 01:32:19 +02:00
Eugen Rochko
f745f95286 New translations strings.xml (Dutch) 2024-06-21 01:32:18 +02:00
Eugen Rochko
cf1c8eb4e3 New translations strings.xml (Interlingua) 2024-06-21 00:23:25 +02:00
Eugen Rochko
6d5ab6b4ba New translations strings.xml (Interlingua) 2024-06-20 23:15:17 +02:00
Eugen Rochko
ab27e36560 New translations strings.xml (Lithuanian) 2024-06-20 23:15:16 +02:00
Eugen Rochko
f368026124 New translations strings.xml (Lithuanian) 2024-06-20 22:10:31 +02:00
Eugen Rochko
bb4c68c6bd New translations strings.xml (Russian) 2024-06-20 17:49:52 +02:00
Grishka
09d68ec197 Merge branch 'master' into donations
# Conflicts:
#	mastodon/build.gradle
2024-06-19 23:12:46 +03:00
Eugen Rochko
b675c14767 New translations full_description.txt (Lithuanian) 2024-06-19 12:04:34 +02:00
Eugen Rochko
5e1b63ba21 New translations full_description.txt (Lithuanian) 2024-06-19 09:29:07 +02:00
Eugen Rochko
5a462df797 New translations strings.xml (Lithuanian) 2024-06-19 09:29:06 +02:00
Grishka
5ac37a38c5 Crash fix 2024-06-17 18:19:34 +03:00
Grishka
960e54f4e6 Donation error string 2024-06-17 18:18:10 +03:00
Grishka
1c6da783ad Add cancellation callback URL 2024-06-17 16:38:00 +03:00
Grishka
bc6b3e1186 Merge branch 'master' into donations 2024-06-15 15:57:36 +03:00
Grishka
f96237b6f1 Donations fixes + success post text from campaign 2024-06-15 00:46:42 +03:00
Grishka
d3344e3e03 Merge branch 'master' into donations 2024-06-15 00:36:09 +03:00
Grishka
16d41fd1fc Make the illustration background transparent 2024-06-14 03:00:40 +03:00
Grishka
6270a3dfdc Donations improvements 2024-06-13 18:58:24 +03:00
Grishka
4e1bf80e12 Make WebViewFragment work with predictive back 2024-06-13 17:08:24 +03:00
Grishka
04129920eb Merge branch 'master' into donations
# Conflicts:
#	mastodon/build.gradle
#	mastodon/src/main/res/values/strings.xml
2024-06-13 16:57:23 +03:00
Grishka
1dd40a77de Merge branch 'master' into donations 2024-05-22 12:22:06 +03:00
Grishka
c94e1f939a Add staging environment toggle 2024-05-21 20:17:46 +03:00
Grishka
2dae00800e Merge branch 'master' into donations
# Conflicts:
#	mastodon/src/main/res/values/strings.xml
2024-05-21 20:08:43 +03:00
Grishka
ea53200e23 Merge branch 'master' into donations 2024-04-21 18:11:32 +03:00
Grishka
79087e3c86 Merge branch 'master' into donations
# Conflicts:
#	mastodon/build.gradle
#	mastodon/src/main/res/values/strings.xml
2024-04-20 07:16:11 +03:00
Grishka
31af0251ea Update endpoint 2024-04-18 02:59:45 +03:00
Grishka
d0d899c73d Check account age for donation eligibility 2024-04-18 02:58:42 +03:00
Grishka
b5aa1a4598 Cache donation campaign responses 2024-04-18 02:55:07 +03:00
Grishka
b9956950b6 Add arrows to currency selector 2024-04-18 02:43:19 +03:00
Grishka
104896ae1b Custom layout for suggested amount buttons 2024-04-15 20:05:12 +03:00
Grishka
977fc2483f Update "masterial" colors to correct ones 2024-04-15 17:46:03 +03:00
Grishka
658177538b Fix dark theme 2024-04-15 17:02:11 +03:00
Grishka
b2d49c3143 Initial implementation of donations 2024-04-15 16:36:59 +03:00
74 changed files with 2632 additions and 351 deletions

View File

@@ -0,0 +1 @@
- Added option to donate to Mastodon in-app when connected to our flagship server. This option will not appear when using a 3rd party server to avoid confusion. Please check if the 3rd party server you're using accepts donations through their website.

View File

@@ -0,0 +1 @@
110.txt

View File

@@ -1,4 +1,4 @@
Mastodon est le plus grand réseau social décentralisé sur Internet. Au lieu dun site Web unique, cest un réseau de millions dutilisateurs dans des communautés indépendantes qui peuvent tous interagir les uns avec les autres, de manière transparente. Peu importe ce que vous êtes, vous pouvez rencontrer des gens passionnés qui publient à ce sujet sur Mastodon !
Mastodon est le plus grand réseau social décentralisé sur Internet. Au lieu dun site Web unique, cest un réseau de millions dutilisateurs dans des communautés indépendantes qui peuvent tous interagir les uns avec les autres, de manière transparente. Peu importe ce que vous aimez, vous pouvez rencontrer des gens passionnés qui en parlent sur Mastodon !
Rejoignez une communauté et créez votre profil. Trouvez et suivez des personnes fascinantes et lisez leurs messages chronologiquement et sans publicité. Exprimez-vous avec des émojis personnalisés, des images, des GIFs, des vidéos et de laudio dans des messages de 500 caractères. Répondez aux sujets de discussions et aux reblogues de nimporte qui pour partager des choses géniales. Trouvez de nouveaux comptes à suivre et des hashtags tendance pour étendre votre réseau.

View File

@@ -1,16 +1,16 @@
Mastodon es le plus grande rete social decentralisate sur internet. In vice que un sol sito web, illo es un rete de milliones de usatores in communitates independente que pote tote interager le un con le altere, perfectemente. Non importa que te interessa, tu pote incontrar personas passionate que posta re illo sur Mastodon!
Mastodon es le rete social decentralisate le plus grande sur internet. In vice que un sol sito web, illo es un rete de milliones de usatores in communitates independente que pote interager le unes con le alteres, transparentemente. Non importa lo que te interessa, tu pote incontrar personas passionate que parla de illo sur Mastodon!
Junge te a un communitate e crea tu profilo. Trova e seque personas fascinante e lege lor messages in un chronogramma chronologic libere de avisos publicitari. Exprime te mesme con emoticone personalisate, imagines, GIFs, videos, e audio in messages de 500-characteres. Responde a messages argumentos e promotiones de quicunque pro compartir grande substantias. Trova nove contos a sequer e hashtags de tendentia pro expander tu rete.
Inscribe te a un communitate e crea tu profilo. Trova e seque personas fascinante e lege lor messages in un chronologia libere de publicitate. Exprime te con emojis personalisate, imagines, GIFs, videos e audio in messages de 500 characteres. Responde a discussiones e impulsa messages de quicunque pro compartir cosas genial. Trova nove contos a sequer e hashtags de tendentia pro expander tu rete.
Mastodon es producite con attention a confidentialitate e securitate. Decide si tu messages es compartite con tu sequaces, solo le gente que tu mentiona, o tote le mundo. Le avisos re contentos te permitte de celar messages que contine material sensibile o provocatori usque tu es preste a interager con illes. Cata communitate ha su proprie lineas guida e moderatores pro mantener su membros secur. Robuste utensiles de blocada e de reporto pro adjutar a impedir abusos.
Mastodon es producite con attention a confidentialitate e securitate. Decide si tu messages es compartite con tu sequitores, con solo le gente que tu mentiona, o con tote le mundo. Le advertimentos de contento te permitte celar messages que contine material sensibile o provocatori usque tu es preste a interager con illos. Cata communitate ha su proprie directivas e moderatores pro mantener su membros secur, e robuste utensiles de blocage e de reportage pro adjutar a impedir abusos.
Altere functiones:
• Modo obscur: lege messages in modo clar, obscur, o francamente nigre
Modo obscur: lege messages in modo clar, obscur, o francamente nigre
• Explora: hashtags de tendentia e contos es a portata de mano
• Notificationes: recipe notificationes circa nove sequaces, responsas, e promotiones
• Compartir: publica directemente sur Mastodon ab qualcunque folio de compartimento in ulle app
• Modo obscur: lege messages in modo clar, obscur, o vermente nigre
Sondages: Demanda al sequitores lor opinion e conta le votos
• Explorar: le hashtags e contos popular es a portata de mano
• Notificationes: sia notificate de nove sequitores, responsas e impulsos
• Compartir: publica directemente sur Mastodon desde le function Compartir de qualcunque app
• Pachydermo: nostre mascotte es un adorabile elephante, e tu lo videra apparer de tempore in tempore
Mastodon es un organisation non lucrative registrate e le disveloppamento es supportate directemente per tu donationes. Il non ha alcun annuncios publicitari, alcun monetisation e capital de hasardo, e nos projecta mantener lo in iste condition.
Mastodon es un organisation registrate sin scopo lucrative e le disveloppamento es sustenite directemente per tu donationes. Il non ha publicitate, ni monetisation, ni capital de risco, e nos intende mantener lo assi.

View File

@@ -1,16 +1,16 @@
Mastodon tai didžiausias decentralizuotas socialinis tinklas internete. Vietoj vienos svetainės tai yra milijonų naudotojų, priklausančių nepriklausomoms bendruomenėms, kurios gali sklandžiai bendrauti tarpusavyje, tinklas. Nesvarbu, kuo domiesi, Mastodon gali sutikti aistringų žmonių, skelbiančių apie tai!
Mastodon tai didžiausias decentralizuotas socialinis tinklas internete. Vietoj vienos svetainės tai yra milijonų naudotojų, priklausančių nepriklausomoms bendruomenėms, kurios gali sklandžiai bendrauti tarpusavyje, tinklas. Nesvarbu, kuo domiesi, Mastodon“ platformoje gali sutikti aistringų žmonių, skelbiančių apie tai!
Prisijunk prie bendruomenės ir susikurk savo profilį. Rask ir sek žavius žmones bei skaityk jų įrašus chronologinėje laiko skalėje be reklamų. Išreikšk save su pasirinktais jaustukais, vaizdais, GIF, vaizdo ir garso įrašais 500 simbolių įrašuose. Atsakyk į gijas ir perdalyk bet kurio asmens įrašus, kad galėtum bendrinti puikiais dalykais. Ieškok naujų paskyrų sekti ir tendencingų saitažodžių, kad praplėstum savo tinklą.
Mastodon sukurtas daugiausia dėmesio skiriant privatumui ir saugumui. Nuspręsk, ar tavo įrašai bus bendrinami tavo sekėjams, tik tavo paminėtiems žmonėms, ar visam pasauliui. Turinio įspėjimai leidžia paslėpti įrašus, kuriuose yra jautrios ar dirginančios medžiagos, kol būsi pasiruošęs (-usi) su jais bendrauti. Kiekviena bendruomenė turi savo gaires ir prižiūrėtojus, kad jos nariai būtų saugūs, o patikimi blokavimo ir pranešimo įrankiai padeda užkirsti kelią piktnaudžiavimui.
Mastodon sukurtas daugiausia dėmesio skiriant privatumui ir saugumui. Nuspręsk, ar tavo įrašai bus bendrinami tavo sekėjams, tik tavo paminėtiems žmonėms, ar visam pasauliui. Turinio įspėjimai leidžia paslėpti įrašus, kuriuose yra jautrios ar dirginančios medžiagos, kol būsi pasiruošęs (-usi) su jais bendrauti. Kiekviena bendruomenė turi savo gaires ir prižiūrėtojus, kad jos nariai būtų saugūs, o patikimi blokavimo ir pranešimo įrankiai padeda užkirsti kelią piktnaudžiavimui.
Daugiau funkcijų:
• Tamsusis režimas: skaityk įrašus šviesiu, tamsiu arba tikru juodu režimu
• Apklausos: paklausk sekėjų nuomonės ir suskaičiuok balsus
• Naršyti: tendencingos saitažodžiai ir paskyros vos nuo vieno prisilietimo
• Pranešimai: gauk pranešimus apie naujus sekėjus, atsakymus ir pasidalijimus
• Bendrinti: skelbk tiesiogiai į Mastodon iš bet kurio bendrinimo lapo bet kurioje programėlėje
• Mielumas: mūsų talismanas žavus drambliukas, kurį retkarčiais pamatysi
• Tamsusis režimas: skaityk įrašus šviesiu, tamsiu arba tikru juodu režimu.
• Apklausos: paklausk sekėjų nuomonės ir suskaičiuok balsus.
• Naršyti: tendencingos saitažodžiai ir paskyros vos nuo vieno prisilietimo.
• Pranešimai: gauk pranešimus apie naujus sekėjus, atsakymus ir pasidalinimus.
• Bendrinti: skelbk tiesiogiai į Mastodon iš bet kurio bendrinimo lapo bet kurioje programėlėje
• Mielumas: mūsų talismanas žavus drambliukas, kurį retkarčiais pamatysi.
Mastodon registruota ne pelno siekianti organizacija, kurios plėtra yra tiesiogiai paremta aukomis. Nėra jokių reklamų, jokių monetizacijos ir rizikos kapitalo, ir mes planuojame, kad taip ir liks.
Mastodon registruota ne pelno siekianti organizacija, kurios plėtra yra tiesiogiai paremta aukomis. Nėra jokių reklamų, jokių monetizacijos ir rizikos kapitalo, ir mes planuojame, kad taip ir liks.

View File

@@ -8,13 +8,13 @@ android {
generateLocaleConfig = true
}
compileSdk 33
compileSdk 34
defaultConfig {
applicationId "org.joinmastodon.android"
minSdk 23
targetSdk 33
versionCode 103
versionName "2.5.2"
targetSdk 34
versionCode 111
versionName "2.6.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -101,7 +101,7 @@ dependencies {
annotationProcessor 'org.parceler:parceler:1.1.12'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
def appCenterSdkVersion = "4.4.2"
def appCenterSdkVersion = "5.0.4"
appcenterPrivateBetaImplementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"
appcenterPrivateBetaImplementation "com.microsoft.appcenter:appcenter-distribute:${appCenterSdkVersion}"
appcenterPublicBetaImplementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"

View File

@@ -4,6 +4,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE"/>
@@ -79,6 +80,7 @@
<data android:mimeType="*/*"/>
</intent-filter>
</activity>
<activity android:name=".DonationFragmentActivity" android:exported="false" android:configChanges="orientation|screenSize" android:windowSoftInputMode="adjustResize"/>
<service android:name=".AudioPlayerService" android:foregroundServiceType="mediaPlayback"/>
<service android:name=".NotificationActionHandlerService" android:exported="false"/>

View File

@@ -88,8 +88,13 @@ public class AudioPlayerService extends Service{
nm=getSystemService(NotificationManager.class);
// registerReceiver(receiver, new IntentFilter(Intent.ACTION_MEDIA_BUTTON));
registerReceiver(receiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
registerReceiver(receiver, new IntentFilter(ACTION_PLAY_PAUSE));
registerReceiver(receiver, new IntentFilter(ACTION_STOP));
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.TIRAMISU){
registerReceiver(receiver, new IntentFilter(ACTION_PLAY_PAUSE), RECEIVER_EXPORTED);
registerReceiver(receiver, new IntentFilter(ACTION_STOP), RECEIVER_EXPORTED);
}else{
registerReceiver(receiver, new IntentFilter(ACTION_PLAY_PAUSE));
registerReceiver(receiver, new IntentFilter(ACTION_STOP));
}
instance=this;
}

View File

@@ -0,0 +1,29 @@
package org.joinmastodon.android;
import android.os.Bundle;
import org.joinmastodon.android.fragments.DonationWebViewFragment;
import androidx.annotation.Nullable;
import me.grishka.appkit.FragmentStackActivity;
// This exists because our designer wanted to avoid extra sheet showing/hiding animations.
// This is the only way to show a fragment on top of a sheet without having to rewrite way too many things.
public class DonationFragmentActivity extends FragmentStackActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(savedInstanceState==null){
DonationWebViewFragment fragment=new DonationWebViewFragment();
fragment.setArguments(getIntent().getBundleExtra("fragmentArgs"));
showFragment(fragment);
overridePendingTransition(R.anim.fragment_enter, R.anim.no_op_300ms);
}
}
@Override
public void finish(){
super.finish();
overridePendingTransition(0, R.anim.fragment_exit);
}
}

View File

@@ -10,7 +10,7 @@ public class GlobalUserPreferences{
public static boolean playGifs;
public static boolean useCustomTabs;
public static boolean altTextReminders, confirmUnfollow, confirmBoost, confirmDeletePost;
public static ThemePreference theme;
public static ThemePreference theme=ThemePreference.AUTO;
private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);

View File

@@ -24,7 +24,6 @@ import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.model.SearchResult;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.io.File;
import java.io.FileInputStream;
@@ -45,8 +44,8 @@ import me.grishka.appkit.utils.WorkerThread;
public class CacheController{
private static final String TAG="CacheController";
private static final int DB_VERSION=3;
private static final WorkerThread databaseThread=new WorkerThread("databaseThread");
private static final Handler uiHandler=new Handler(Looper.getMainLooper());
public static final WorkerThread databaseThread=new WorkerThread("databaseThread");
public static final Handler uiHandler=new Handler(Looper.getMainLooper());
private final String accountID;
private DatabaseHelper db;
@@ -467,9 +466,4 @@ public class CacheController{
db.execSQL("ALTER TABLE `notifications_mentions` ADD `time` INTEGER NOT NULL DEFAULT 0");
}
}
@FunctionalInterface
private interface DatabaseRunnable{
void run(SQLiteDatabase db) throws IOException;
}
}

View File

@@ -0,0 +1,10 @@
package org.joinmastodon.android.api;
import android.database.sqlite.SQLiteDatabase;
import java.io.IOException;
@FunctionalInterface
public interface DatabaseRunnable{
void run(SQLiteDatabase db) throws IOException;
}

View File

@@ -12,10 +12,12 @@ import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.api.gson.IsoInstantTypeAdapter;
import org.joinmastodon.android.api.gson.IsoLocalDateTypeAdapter;
import org.joinmastodon.android.api.session.AccountSession;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.time.Instant;
@@ -29,6 +31,8 @@ import java.util.concurrent.TimeUnit;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import me.grishka.appkit.utils.WorkerThread;
import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
@@ -49,8 +53,11 @@ public class MastodonAPIController{
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.cache(new Cache(new File(MastodonApp.context.getCacheDir(), "http"), 10*1024*1024))
.build();
private static final CacheControl NO_CACHE_WHATSOEVER=new CacheControl.Builder().noCache().noStore().build();
private AccountSession session;
static{
@@ -80,6 +87,9 @@ public class MastodonAPIController{
if(token!=null)
builder.header("Authorization", "Bearer "+token);
if(!req.cacheable)
builder.cacheControl(NO_CACHE_WHATSOEVER);
if(req.headers!=null){
for(Map.Entry<String, String> header:req.headers.entrySet()){
builder.header(header.getKey(), header.getValue());

View File

@@ -46,6 +46,7 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
boolean canceled;
Map<String, String> headers;
long timeout;
boolean cacheable;
private ProgressDialog progressDialog;
protected boolean removeUnsupportedItems;
@@ -132,6 +133,10 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
this.timeout=timeout;
}
protected void setCacheable(){
cacheable=true;
}
protected String getPathPrefix(){
return "/api/v1";
}

View File

@@ -0,0 +1,40 @@
package org.joinmastodon.android.api.requests.catalog;
import android.net.Uri;
import android.text.TextUtils;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.donations.DonationCampaign;
public class GetDonationCampaigns extends MastodonAPIRequest<DonationCampaign>{
private final String locale, seed, source;
private boolean staging;
public GetDonationCampaigns(String locale, String seed, String source){
super(HttpMethod.GET, null, DonationCampaign.class);
this.locale=locale;
this.seed=seed;
this.source=source;
setCacheable();
}
public void setStaging(boolean staging){
this.staging=staging;
}
@Override
public Uri getURL(){
Uri.Builder builder=new Uri.Builder()
.scheme("https")
.authority("api.joinmastodon.org")
.path("/v1/donations/campaigns/active")
.appendQueryParameter("platform", "android")
.appendQueryParameter("locale", locale)
.appendQueryParameter("seed", seed);
if(staging)
builder.appendQueryParameter("environment", "staging");
if(!TextUtils.isEmpty(source))
builder.appendQueryParameter("source", source);
return builder.build();
}
}

View File

@@ -33,7 +33,8 @@ import org.joinmastodon.android.model.TimelineMarkers;
import org.joinmastodon.android.model.Token;
import org.joinmastodon.android.utils.ObjectIdComparator;
import java.io.File;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@@ -44,6 +45,7 @@ import me.grishka.appkit.api.ErrorResponse;
public class AccountSession{
private static final String TAG="AccountSession";
private static final int MIN_DAYS_ACCOUNT_AGE_FOR_DONATIONS=28;
public Token token;
public Account self;
@@ -276,4 +278,12 @@ public class AccountSession{
public void setNotificationsMentionsOnly(boolean mentionsOnly){
getRawLocalPreferences().edit().putBoolean("notificationsMentionsOnly", mentionsOnly).apply();
}
public boolean isEligibleForDonations(){
return ("mastodon.social".equalsIgnoreCase(domain) || "mastodon.online".equalsIgnoreCase(domain)) && self.createdAt.isBefore(Instant.now().minus(MIN_DAYS_ACCOUNT_AGE_FOR_DONATIONS, ChronoUnit.DAYS));
}
public int getDonationSeed(){
return Math.abs(getFullUsername().hashCode())%100;
}
}

View File

@@ -3,11 +3,16 @@ package org.joinmastodon.android.api.session;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
@@ -18,11 +23,13 @@ import org.joinmastodon.android.E;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.CacheController;
import org.joinmastodon.android.api.DatabaseRunnable;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.PushSubscriptionManager;
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
import org.joinmastodon.android.api.requests.filters.GetLegacyFilters;
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
import org.joinmastodon.android.api.requests.instance.GetInstance;
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
import org.joinmastodon.android.events.EmojiUpdatedEvent;
@@ -30,9 +37,10 @@ import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Application;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.EmojiCategory;
import org.joinmastodon.android.model.LegacyFilter;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.LegacyFilter;
import org.joinmastodon.android.model.Token;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.io.File;
import java.io.FileInputStream;
@@ -60,6 +68,7 @@ public class AccountSessionManager{
private static final String TAG="AccountSessionManager";
public static final String SCOPE="read write follow push";
public static final String REDIRECT_URI="mastodon-android-auth://callback";
private static final int DB_VERSION=1;
private static final AccountSessionManager instance=new AccountSessionManager();
@@ -73,6 +82,8 @@ public class AccountSessionManager{
private String lastActiveAccountID;
private SharedPreferences prefs;
private boolean loadedInstances;
private DatabaseHelper db;
private final Runnable databaseCloseRunnable=this::closeDatabase;
public static AccountSessionManager getInstance(){
return instance;
@@ -94,7 +105,7 @@ public class AccountSessionManager{
Log.e(TAG, "Error loading accounts", x);
}
lastActiveAccountID=prefs.getString("lastActiveAccount", null);
MastodonAPIController.runInBackground(()->readInstanceInfo(domains));
readInstanceInfo(domains);
maybeUpdateShortcuts();
}
@@ -270,11 +281,11 @@ public class AccountSessionManager{
}
}
if(loadedInstances){
maybeUpdateCustomEmojis(domains);
maybeUpdateInstanceInfo(domains);
}
}
private void maybeUpdateCustomEmojis(Set<String> domains){
private void maybeUpdateInstanceInfo(Set<String> domains){
long now=System.currentTimeMillis();
for(String domain:domains){
Long lastUpdated=instancesLastUpdated.get(domain);
@@ -388,7 +399,7 @@ public class AccountSessionManager{
}
if(!loadedInstances){
loadedInstances=true;
maybeUpdateCustomEmojis(domains);
MastodonAPIController.runInBackground(()->maybeUpdateInstanceInfo(domains));
}
}
@@ -450,6 +461,68 @@ public class AccountSessionManager{
}
}
private void closeDelayed(){
CacheController.databaseThread.postRunnable(databaseCloseRunnable, 10_000);
}
public void closeDatabase(){
if(db!=null){
if(BuildConfig.DEBUG)
Log.d(TAG, "closeDatabase");
db.close();
db=null;
}
}
private void cancelDelayedClose(){
if(db!=null){
CacheController.databaseThread.handler.removeCallbacks(databaseCloseRunnable);
}
}
private SQLiteDatabase getOrOpenDatabase(){
if(db==null)
db=new DatabaseHelper();
return db.getWritableDatabase();
}
private void runOnDbThread(DatabaseRunnable r){
cancelDelayedClose();
CacheController.databaseThread.postRunnable(()->{
try{
SQLiteDatabase db=getOrOpenDatabase();
r.run(db);
}catch(SQLiteException|IOException x){
Log.w(TAG, x);
}finally{
closeDelayed();
}
}, 0);
}
public void runIfDonationCampaignNotDismissed(String id, Runnable action){
runOnDbThread(db->{
try(Cursor cursor=db.query("dismissed_donation_campaigns", null, "id=?", new String[]{id}, null, null, null)){
if(!cursor.moveToFirst()){
UiUtils.runOnUiThread(action);
}
}
});
}
public void markDonationCampaignAsDismissed(String id){
runOnDbThread(db->{
ContentValues values=new ContentValues();
values.put("id", id);
values.put("dismissed_at", System.currentTimeMillis());
db.insert("dismissed_donation_campaigns", null, values);
});
}
public void clearDismissedDonationCampaigns(){
runOnDbThread(db->db.delete("dismissed_donation_campaigns", null, null));
}
private static class SessionsStorageWrapper{
public List<AccountSession> accounts;
}
@@ -459,4 +532,24 @@ public class AccountSessionManager{
public List<Emoji> emojis;
public long lastUpdated;
}
private static class DatabaseHelper extends SQLiteOpenHelper{
public DatabaseHelper(){
super(MastodonApp.context, "accounts.db", null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db){
db.execSQL("""
CREATE TABLE `dismissed_donation_campaigns` (
`id` text PRIMARY KEY,
`dismissed_at` bigint
)""");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
}
}
}

View File

@@ -0,0 +1,9 @@
package org.joinmastodon.android.events;
public class DismissDonationCampaignBannerEvent{
public final String campaignID;
public DismissDonationCampaignBannerEvent(String campaignID){
this.campaignID=campaignID;
}
}

View File

@@ -666,7 +666,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
proceed.run();
}, status.account, accountID).show();
}else if(!GlobalUserPreferences.isOptedOutOfPreReplySheet(GlobalUserPreferences.PreReplySheetType.OLD_POST, null, null) &&
status.createdAt.isBefore(Instant.now().minus(90, ChronoUnit.DAYS))){
status.createdAt.isBefore(Instant.now().minus(90, ChronoUnit.DAYS)) && !status.account.id.equals(AccountSessionManager.get(accountID).self.id)){
new OldPostPreReplySheet(getActivity(), notAgain->{
if(notAgain)
GlobalUserPreferences.optOutOfPreReplySheet(GlobalUserPreferences.PreReplySheetType.OLD_POST, null, null);

View File

@@ -544,7 +544,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements ComposeE
ignoreSelectionChanges=true;
mainEditText.setSelection(mainEditText.length());
ignoreSelectionChanges=false;
mediaViewController.onViewCreated(savedInstanceState);;
mediaViewController.onViewCreated(savedInstanceState);
}else{
String prefilledText=getArguments().getString("prefilledText");
if(!TextUtils.isEmpty(prefilledText)){
@@ -766,6 +766,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements ComposeE
sendingOverlay=null;
removeBackCallback(sendingBackButtonBlocker);
removeBackCallback(discardConfirmationCallback);
removeBackCallback(emojiKeyboardHider);
if(editingStatus==null){
E.post(new StatusCreatedEvent(result, accountID));
if(replyTo!=null){

View File

@@ -0,0 +1,96 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebResourceRequest;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.DismissDonationCampaignBannerEvent;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import java.util.Objects;
import me.grishka.appkit.Nav;
public class DonationWebViewFragment extends WebViewFragment{
public static final String SUCCESS_URL="https://sponsor.joinmastodon.org/donate/success";
public static final String FAILURE_URL="https://sponsor.joinmastodon.org/donate/failure";
public static final String CANCEL_URL="https://sponsor.joinmastodon.org/donate/cancel";
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(BuildConfig.DEBUG){
setHasOptionsMenu(true);
}
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
webView.loadUrl(Objects.requireNonNull(getArguments().getString("url")));
}
@Override
protected boolean shouldOverrideUrlLoading(WebResourceRequest req){
String url=req.getUrl().buildUpon().clearQuery().fragment(null).build().toString();
if(url.equalsIgnoreCase(SUCCESS_URL)){
onSuccess();
return true;
}else if(url.equalsIgnoreCase(FAILURE_URL)){
onFailure();
return true;
}else if(url.equalsIgnoreCase(CANCEL_URL)){
onCancel();
return true;
}
return false;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
super.onCreateOptionsMenu(menu, inflater);
if(BuildConfig.DEBUG){
menu.add(0, 0, 0, "Simulate success");
menu.add(0, 1, 0, "Simulate failure");
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
if(item.getItemId()==0)
onSuccess();
else if(item.getItemId()==1)
onFailure();
return super.onOptionsItemSelected(item);
}
private void onFailure(){
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.error)
.setMessage(R.string.donation_server_error)
.setPositiveButton(R.string.ok, null)
.setOnDismissListener(dlg->Nav.finish(this))
.show();
}
private void onSuccess(){
String campaignID=getArguments().getString("campaignID");
AccountSessionManager.getInstance().markDonationCampaignAsDismissed(campaignID);
E.post(new DismissDonationCampaignBannerEvent(campaignID));
getActivity().setResult(Activity.RESULT_OK, new Intent().putExtra("postText", getArguments().getString("successPostText")));
getActivity().finish();
}
private void onCancel(){
getActivity().finish();
}
}

View File

@@ -5,15 +5,23 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
import android.widget.Button;
@@ -26,14 +34,17 @@ import android.widget.Toolbar;
import com.squareup.otto.Subscribe;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.requests.catalog.GetDonationCampaigns;
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
import org.joinmastodon.android.api.requests.timelines.GetListTimeline;
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.DismissDonationCampaignBannerEvent;
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
import org.joinmastodon.android.fragments.settings.SettingsMainFragment;
import org.joinmastodon.android.model.CacheablePaginatedResponse;
@@ -41,8 +52,11 @@ import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.FollowList;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.TimelineMarkers;
import org.joinmastodon.android.model.donations.DonationCampaign;
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.sheets.DonationSheet;
import org.joinmastodon.android.ui.sheets.DonationSuccessfulSheet;
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
import org.joinmastodon.android.ui.viewcontrollers.HomeTimelineMenuController;
import org.joinmastodon.android.ui.viewcontrollers.ToolbarDropdownMenuController;
@@ -53,6 +67,7 @@ import org.parceler.Parcels;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import androidx.annotation.NonNull;
@@ -64,8 +79,11 @@ import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.BottomSheet;
public class HomeTimelineFragment extends StatusListFragment implements ToolbarDropdownMenuController.HostFragment{
private static final int DONATION_RESULT=211;
private ImageButton fab;
private LinearLayout listsDropdown;
private FixedAspectRatioImageView listsDropdownArrow;
@@ -81,9 +99,13 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD
private FollowList currentList;
private MergeRecyclerAdapter mergeAdapter;
private DiscoverInfoBannerHelper localTimelineBannerHelper;
private View donationBanner;
private boolean donationBannerDismissing;
private String maxID;
private String lastSavedMarkerID;
private DonationCampaign currentDonationCampaign;
private BottomSheet donationSheet;
public HomeTimelineFragment(){
setListLayoutId(R.layout.fragment_timeline);
@@ -93,6 +115,32 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
localTimelineBannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.LOCAL_TIMELINE, accountID);
if(AccountSessionManager.get(accountID).isEligibleForDonations()){
GetDonationCampaigns req=new GetDonationCampaigns(Locale.getDefault().toLanguageTag().replace('-', '_'), String.valueOf(AccountSessionManager.get(accountID).getDonationSeed()), null);
if(getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE).getBoolean("donationsStaging", false)){
req.setStaging(true);
}
req.setCallback(new Callback<>(){
@Override
public void onSuccess(DonationCampaign result){
if(result==null)
return;
AccountSessionManager.getInstance().runIfDonationCampaignNotDismissed(result.id, ()->showDonationBanner(result));
}
@Override
public void onError(ErrorResponse error){}
})
.execNoAuth("");
}
E.register(this);
}
@Override
public void onDestroy(){
super.onDestroy();
E.unregister(this);
}
@Override
@@ -230,9 +278,10 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD
});
if(GithubSelfUpdater.needSelfUpdating()){
E.register(this);
updateUpdateState(GithubSelfUpdater.getInstance().getState());
}
if(currentDonationCampaign!=null)
showDonationBanner(currentDonationCampaign);
}
@Override
@@ -584,9 +633,8 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD
@Override
public void onDestroyView(){
super.onDestroyView();
if(GithubSelfUpdater.needSelfUpdating()){
E.unregister(this);
}
donationBanner=null;
donationBannerDismissing=false;
}
private void updateUpdateState(GithubSelfUpdater.UpdateState state){
@@ -599,6 +647,13 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD
updateUpdateState(ev.state);
}
@Subscribe
public void onDismissDonationCampaignBanner(DismissDonationCampaignBannerEvent ev){
if(currentDonationCampaign!=null && ev.campaignID.equals(currentDonationCampaign.id)){
dismissDonationBanner();
}
}
@Override
protected boolean shouldRemoveAccountPostsWhenUnfollowing(){
return true;
@@ -653,6 +708,17 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD
super.onDataLoaded(d, more);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode==DONATION_RESULT){
if(donationSheet!=null)
donationSheet.dismissWithoutAnimation();
if(resultCode==Activity.RESULT_OK){
new DonationSuccessfulSheet(getActivity(), accountID, data.getStringExtra("postText")).showWithoutAnimation();
}
}
}
private String getCurrentListTitle(){
return switch(listMode){
case FOLLOWING -> getString(R.string.timeline_following);
@@ -661,6 +727,77 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD
};
}
private void showDonationBanner(DonationCampaign campaign){
if(getActivity()==null)
return;
currentDonationCampaign=campaign;
if(donationBanner==null){
ViewStub stub=contentView.findViewById(R.id.donation_banner);
donationBanner=stub.inflate();
donationBanner.findViewById(R.id.banner_dismiss).setOnClickListener(v->{
AccountSessionManager.getInstance().markDonationCampaignAsDismissed(currentDonationCampaign.id);
dismissDonationBanner();
});
donationBanner.setOnClickListener(v->openDonationSheet());
}else{
donationBanner.setVisibility(View.VISIBLE);
}
TextView text=donationBanner.findViewById(R.id.banner_text);
SpannableStringBuilder ssb=new SpannableStringBuilder(campaign.bannerMessage);
ssb.append(' ');
int start=ssb.length();
ssb.append(campaign.bannerButtonText);
ssb.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.masterialDark_colorGoldenrodContainer, getActivity().getTheme())), start, ssb.length(), 0);
ssb.setSpan(new UnderlineSpan(), start, ssb.length(), 0);
ssb.setSpan(new TypefaceSpan("sans-serif-medium"), start, ssb.length(), 0);
text.setText(ssb);
donationBanner.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw(){
donationBanner.getViewTreeObserver().removeOnPreDrawListener(this);
AnimatorSet set=new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(donationBanner, View.TRANSLATION_Y, donationBanner.getHeight(), 0),
ObjectAnimator.ofFloat(fab, View.TRANSLATION_Y, -donationBanner.getHeight())
);
set.setDuration(250);
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
set.start();
return true;
}
});
}
private void dismissDonationBanner(){
if(donationBanner==null || donationBannerDismissing)
return;
AnimatorSet set=new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(donationBanner, View.TRANSLATION_Y, donationBanner.getHeight()),
ObjectAnimator.ofFloat(fab, View.TRANSLATION_Y, 0)
);
set.setDuration(250);
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
set.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animation){
donationBanner.setVisibility(View.GONE);
donationBannerDismissing=false;
}
});
donationBannerDismissing=true;
set.start();
currentDonationCampaign=null;
}
private void openDonationSheet(){
donationSheet=new DonationSheet(getActivity(), currentDonationCampaign, accountID, intent->startActivityForResult(intent, DONATION_RESULT));
donationSheet.setOnDismissListener(dialog->donationSheet=null);
donationSheet.show();
}
private enum ListMode{
FOLLOWING,
LOCAL,

View File

@@ -0,0 +1,102 @@
package org.joinmastodon.android.fragments;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.api.MastodonErrorResponse;
import me.grishka.appkit.Nav;
import me.grishka.appkit.fragments.LoaderFragment;
public abstract class WebViewFragment extends LoaderFragment{
private static final String TAG="WebViewFragment";
protected WebView webView;
private Runnable backCallback=this::onGoBack;
private boolean backCallbackSet;
@Override
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
webView=new WebView(getActivity());
webView.setWebChromeClient(new WebChromeClient(){
@Override
public void onReceivedTitle(WebView view, String title){
setTitle(title);
}
});
webView.setWebViewClient(new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url){
if(BuildConfig.DEBUG){
Log.d(TAG, "onPageFinished: "+url);
}
dataLoaded();
updateBackCallback();
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error){
if(!loaded){
onError(new MastodonErrorResponse(error.getDescription().toString(), -1, null));
updateBackCallback();
}
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request){
return WebViewFragment.this.shouldOverrideUrlLoading(request);
}
@Override
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload){
updateBackCallback();
}
});
webView.getSettings().setJavaScriptEnabled(true);
return webView;
}
@Override
protected void doLoadData(){
}
@Override
public void onRefresh(){
webView.reload();
}
@Override
public void onToolbarNavigationClick(){
Nav.finish(this);
}
private void updateBackCallback(){
boolean canGoBack=webView.canGoBack();
if(canGoBack!=backCallbackSet){
if(canGoBack){
addBackCallback(backCallback);
backCallbackSet=true;
}else{
removeBackCallback(backCallback);
backCallbackSet=false;
}
}
}
private void onGoBack(){
if(webView.canGoBack())
webView.goBack();
}
protected abstract boolean shouldOverrideUrlLoading(WebResourceRequest req);
}

View File

@@ -144,6 +144,7 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
@Override
public void onDestroy(){
removeBackCallback(exitQueryModeCallback);
super.onDestroy();
}
@@ -690,7 +691,7 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
boolean found=false;
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder.getAbsoluteAdapterPosition()==mergeAdapter.getPositionForAdapter(adapter)+idx && holder instanceof InstanceViewHolder ivh){
if(holder instanceof InstanceViewHolder ivh && holder.getAbsoluteAdapterPosition()==mergeAdapter.getPositionForAdapter(adapter)+idx){
ivh.radioButton.setChecked(false);
found=true;
break;

View File

@@ -100,6 +100,8 @@ public class InstanceChooserLoginFragment extends InstanceCatalogFragment{
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<CatalogInstance> result){
if(getActivity()==null)
return;
data.clear();
data.addAll(sortInstances(result));
updateFilteredList();

View File

@@ -97,6 +97,12 @@ public class EditFilterFragment extends BaseSettingsFragment<Void>{
setRetainInstance(true);
}
@Override
public void onDestroy(){
removeBackCallback(confirmCallback);
super.onDestroy();
}
@Override
protected void doLoadData(int offset, int count){}

View File

@@ -1,5 +1,7 @@
package org.joinmastodon.android.fragments.settings;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Toast;
@@ -9,6 +11,7 @@ import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
import org.joinmastodon.android.updater.GithubSelfUpdater;
@@ -18,6 +21,8 @@ import java.util.List;
import me.grishka.appkit.Nav;
public class SettingsDebugFragment extends BaseSettingsFragment<Void>{
private CheckableListItem<Void> donationsStagingItem;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
@@ -28,7 +33,9 @@ public class SettingsDebugFragment extends BaseSettingsFragment<Void>{
selfUpdateItem=new ListItem<>("Force self-update", null, this::onForceSelfUpdateClick),
resetUpdateItem=new ListItem<>("Reset self-updater", null, this::onResetUpdaterClick),
new ListItem<>("Reset search info banners", null, this::onResetDiscoverBannersClick),
new ListItem<>("Reset pre-reply sheets", null, this::onResetPreReplySheetsClick)
new ListItem<>("Reset pre-reply sheets", null, this::onResetPreReplySheetsClick),
new ListItem<>("Clear dismissed donation campaigns", null, this::onClearDismissedCampaignsClick),
donationsStagingItem=new CheckableListItem<>("Use staging environment for donations", null, CheckableListItem.Style.SWITCH, getPrefs().getBoolean("donationsStaging", false), this::toggleCheckableItem)
));
if(!GithubSelfUpdater.needSelfUpdating()){
resetUpdateItem.isEnabled=selfUpdateItem.isEnabled=false;
@@ -39,6 +46,12 @@ public class SettingsDebugFragment extends BaseSettingsFragment<Void>{
@Override
protected void doLoadData(int offset, int count){}
@Override
public void onStop(){
super.onStop();
getPrefs().edit().putBoolean("donationsStaging", donationsStagingItem.checked).apply();
}
private void onTestEmailConfirmClick(ListItem<?> item){
AccountSession sess=AccountSessionManager.getInstance().getAccount(accountID);
sess.activated=false;
@@ -70,9 +83,18 @@ public class SettingsDebugFragment extends BaseSettingsFragment<Void>{
Toast.makeText(getActivity(), "Pre-reply sheets were reset", Toast.LENGTH_SHORT).show();
}
private void onClearDismissedCampaignsClick(ListItem<?> item){
AccountSessionManager.getInstance().clearDismissedDonationCampaigns();
Toast.makeText(getActivity(), "Dismissed campaigns cleared. Restart app to see your current campaign, if any", Toast.LENGTH_LONG).show();
}
private void restartUI(){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.goClearingStack(getActivity(), HomeFragment.class, args);
}
private SharedPreferences getPrefs(){
return getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE);
}
}

View File

@@ -1,10 +1,14 @@
package org.joinmastodon.android.fragments.settings;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.otto.Subscribe;
@@ -12,27 +16,38 @@ import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.E;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.catalog.GetDonationCampaigns;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
import org.joinmastodon.android.model.donations.DonationCampaign;
import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.sheets.AccountSwitcherSheet;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.sheets.AccountSwitcherSheet;
import org.joinmastodon.android.ui.sheets.DonationSheet;
import org.joinmastodon.android.ui.sheets.DonationSuccessfulSheet;
import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.utils.MergeRecyclerAdapter;
public class SettingsMainFragment extends BaseSettingsFragment<Void>{
private static final int DONATION_RESULT=433;
private boolean loggedOut;
private HideableSingleViewRecyclerAdapter bannerAdapter;
private Button updateButton1, updateButton2;
private TextView updateText;
private DonationSheet donationSheet;
private Runnable updateDownloadProgressUpdater=new Runnable(){
@Override
public void run(){
@@ -49,21 +64,26 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
super.onCreate(savedInstanceState);
setTitle(R.string.settings);
setSubtitle(AccountSessionManager.get(accountID).getFullUsername());
onDataLoaded(List.of(
ArrayList<ListItem<Void>> items=new ArrayList<>();
if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){
items.add(new ListItem<>("Debug settings", null, R.drawable.ic_settings_24px, i->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null, 0, true));
}
items.addAll(List.of(
new ListItem<>(R.string.settings_behavior, 0, R.drawable.ic_settings_24px, this::onBehaviorClick),
new ListItem<>(R.string.settings_display, 0, R.drawable.ic_style_24px, this::onDisplayClick),
new ListItem<>(R.string.settings_privacy, 0, R.drawable.ic_privacy_tip_24px, this::onPrivacyClick),
new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_filter_alt_24px, this::onFiltersClick),
new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_notifications_24px, this::onNotificationsClick),
new ListItem<>(AccountSessionManager.get(accountID).domain, getString(R.string.settings_server_explanation), R.drawable.ic_dns_24px, this::onServerClick),
new ListItem<>(getString(R.string.about_app, getString(R.string.app_name)), null, R.drawable.ic_info_24px, this::onAboutClick, null, 0, true),
new ListItem<>(R.string.manage_accounts, 0, R.drawable.ic_switch_account_24px, this::onManageAccountsClick),
new ListItem<>(R.string.log_out, 0, R.drawable.ic_logout_24px, this::onLogOutClick, R.attr.colorM3Error, false)
new ListItem<>(getString(R.string.about_app, getString(R.string.app_name)), null, R.drawable.ic_info_24px, this::onAboutClick, null, 0, true)
));
if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){
data.add(0, new ListItem<>("Debug settings", null, R.drawable.ic_settings_24px, i->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null, 0, true));
if(AccountSessionManager.get(accountID).isEligibleForDonations()){
items.add(new ListItem<>(R.string.settings_donate, 0, R.drawable.ic_volunteer_activism_24px, this::onDonateClick));
items.add(new ListItem<>(R.string.settings_manage_donations, 0, R.drawable.ic_settings_heart_24px, this::onManageDonationClick, 0, true));
}
items.add(new ListItem<>(R.string.manage_accounts, 0, R.drawable.ic_switch_account_24px, this::onManageAccountsClick));
items.add(new ListItem<>(R.string.log_out, 0, R.drawable.ic_logout_24px, this::onLogOutClick, R.attr.colorM3Error, false));
onDataLoaded(items);
AccountSession session=AccountSessionManager.get(accountID);
session.reloadPreferences(null);
@@ -117,6 +137,17 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode==DONATION_RESULT){
if(donationSheet!=null)
donationSheet.dismissWithoutAnimation();
if(resultCode==Activity.RESULT_OK){
new DonationSuccessfulSheet(getActivity(), accountID, data.getStringExtra("postText")).showWithoutAnimation();
}
}
}
private Bundle makeFragmentArgs(){
Bundle args=new Bundle();
args.putString("account", accountID);
@@ -167,6 +198,39 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
.show();
}
private void onDonateClick(ListItem<?> item){
GetDonationCampaigns req=new GetDonationCampaigns(Locale.getDefault().toLanguageTag().replace('-', '_'), String.valueOf(AccountSessionManager.get(accountID).getDonationSeed()), "menu");
if(getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE).getBoolean("donationsStaging", false)){
req.setStaging(true);
}
req.setCallback(new Callback<>(){
@Override
public void onSuccess(DonationCampaign result){
Activity activity=getActivity();
if(activity==null)
return;
if(result==null){
Toast.makeText(activity, "No campaign available (server misconfiguration?)", Toast.LENGTH_SHORT).show();
return;
}
donationSheet=new DonationSheet(getActivity(), result, accountID, intent->startActivityForResult(intent, DONATION_RESULT));
donationSheet.setOnDismissListener(dialog->donationSheet=null);
donationSheet.show();
}
@Override
public void onError(ErrorResponse error){
error.showToast(getActivity());
}
})
.wrapProgress(getActivity(), R.string.loading, true)
.execNoAuth("");
}
private void onManageDonationClick(ListItem<?> item){
UiUtils.launchWebBrowser(getActivity(), "https://sponsor.staging.joinmastodon.org/donate/manage");
}
@Subscribe
public void onSelfUpdateStateChanged(SelfUpdateStateChangedEvent ev){
updateUpdateBanner();

View File

@@ -37,6 +37,7 @@ public class Card extends BaseModel{
public List<History> history;
public Instant publishedAt;
public Account authorAccount;
public List<Author> authors;
public transient Drawable blurhashPlaceholder;
@@ -52,6 +53,11 @@ public class Card extends BaseModel{
}
if(authorAccount!=null)
authorAccount.postprocess();
if(authors!=null){
for(Author a:authors){
a.postprocess();
}
}
}
@Override
@@ -85,4 +91,19 @@ public class Card extends BaseModel{
@SerializedName("rich")
RICH
}
@Parcel
public static class Author extends BaseModel{
@RequiredField
public String name;
public String url;
public Account account;
@Override
public void postprocess() throws ObjectValidationException{
super.postprocess();
if(account!=null)
account.postprocess();
}
}
}

View File

@@ -0,0 +1,34 @@
package org.joinmastodon.android.model.donations;
import org.joinmastodon.android.api.AllFieldsAreRequired;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
import org.joinmastodon.android.model.BaseModel;
import java.util.Map;
@AllFieldsAreRequired
public class DonationCampaign extends BaseModel{
public String id;
public String bannerMessage;
public String bannerButtonText;
public String donationMessage;
public String donationButtonText;
public Amounts amounts;
public String defaultCurrency;
public String donationUrl;
public String donationSuccessPost;
@Override
public void postprocess() throws ObjectValidationException{
super.postprocess();
amounts.postprocess();
}
public static class Amounts extends BaseModel{
public Map<String, long[]> oneTime;
@RequiredField
public Map<String, long[]> monthly;
public Map<String, long[]> yearly;
}
}

View File

@@ -5,6 +5,7 @@ import android.text.TextUtils;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Card;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
@@ -26,12 +27,14 @@ public class CardViewModel{
this.parentObject=parentObject;
this.imageRequest=TextUtils.isEmpty(card.image) ? null : new UrlImageLoaderRequest(card.image, V.dp(width), V.dp(height));
if(card.authorAccount!=null){
parsedAuthorName=new SpannableStringBuilder(card.authorAccount.displayName);
Account authorAccount=getAuthorAccount();
if(authorAccount!=null){
parsedAuthorName=new SpannableStringBuilder(authorAccount.displayName);
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
HtmlParser.parseCustomEmoji(parsedAuthorName, card.authorAccount.emojis);
HtmlParser.parseCustomEmoji(parsedAuthorName, authorAccount.emojis);
authorNameEmojiHelper.setText(parsedAuthorName);
authorAvaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? card.authorAccount.avatar : card.authorAccount.avatarStatic, V.dp(50), V.dp(50));
authorAvaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? authorAccount.avatar : authorAccount.avatarStatic, V.dp(50), V.dp(50));
}else{
parsedAuthorName=null;
authorAvaRequest=null;
@@ -39,7 +42,7 @@ public class CardViewModel{
}
public int getImageCount(){
return 1+(card.authorAccount!=null ? (1+authorNameEmojiHelper.getImageCount()) : 0);
return 1+(getAuthorAccount()!=null ? (1+authorNameEmojiHelper.getImageCount()) : 0);
}
public ImageLoaderRequest getImageRequest(int index){
@@ -49,4 +52,11 @@ public class CardViewModel{
default -> authorNameEmojiHelper.getImageRequest(index-2);
};
}
public Account getAuthorAccount(){
if(card.authors!=null && !card.authors.isEmpty() && card.authors.get(0).account!=null)
return card.authors.get(0).account;
else
return card.authorAccount;
}
}

View File

@@ -133,7 +133,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
more=findViewById(R.id.more);
extraText=findViewById(R.id.extra_text);
clickableThing=findViewById(R.id.clickable_thing);
clickableThing.setOnClickListener(this::onAvaClick);
if(clickableThing!=null)
clickableThing.setOnClickListener(this::onAvaClick);
avatar.setOutlineProvider(OutlineProviders.roundedRect(10));
avatar.setClipToOutline(true);
more.setOnClickListener(this::onMoreClick);
@@ -272,8 +273,10 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
extraText.setText(item.extraText);
}
more.setVisibility(item.inset ? View.GONE : View.VISIBLE);
clickableThing.setClickable(!item.inset);
clickableThing.setContentDescription(item.parentFragment.getString(R.string.avatar_description, item.user.acct));
if(clickableThing!=null){
clickableThing.setClickable(!item.inset);
clickableThing.setContentDescription(item.parentFragment.getString(R.string.avatar_description, item.user.acct));
}
}
@Override

View File

@@ -0,0 +1,353 @@
package org.joinmastodon.android.ui.sheets;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import org.joinmastodon.android.DonationFragmentActivity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.DonationWebViewFragment;
import org.joinmastodon.android.model.donations.DonationCampaign;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.CurrencyAmountInput;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Currency;
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import androidx.annotation.NonNull;
import me.grishka.appkit.utils.CustomViewHelper;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.BottomSheet;
public class DonationSheet extends BottomSheet{
private final DonationCampaign campaign;
private final String accountID;
private final Consumer<Intent> startCallback;
private DonationFrequency frequency=DonationFrequency.MONTHLY;
private View onceTab, monthlyTab, yearlyTab;
private int currentTab;
private CurrencyAmountInput amountField;
private ToggleButton[] suggestedAmountButtons=new ToggleButton[6];
private View button;
private TextView buttonText;
private Activity activity;
public DonationSheet(@NonNull Activity activity, DonationCampaign campaign, String accountID, Consumer<Intent> startCallback){
super(activity);
this.campaign=campaign;
this.accountID=accountID;
this.activity=activity;
this.startCallback=startCallback;
Context context=activity;
View content=context.getSystemService(LayoutInflater.class).inflate(R.layout.sheet_donation, null);
setContentView(content);
setNavigationBarBackground(new ColorDrawable(UiUtils.alphaBlendColors(UiUtils.getThemeColor(context, R.attr.colorM3Surface),
UiUtils.getThemeColor(context, R.attr.colorM3Primary), 0.05f)), !UiUtils.isDarkTheme());
TextView text=findViewById(R.id.text);
text.setText(campaign.donationMessage);
onceTab=findViewById(R.id.once);
monthlyTab=findViewById(R.id.monthly);
yearlyTab=findViewById(R.id.yearly);
onceTab.setOnClickListener(this::onTabClick);
monthlyTab.setOnClickListener(this::onTabClick);
yearlyTab.setOnClickListener(this::onTabClick);
if(campaign.amounts.yearly==null)
yearlyTab.setVisibility(View.GONE);
if(campaign.amounts.oneTime==null)
onceTab.setVisibility(View.GONE);
if(campaign.amounts.monthly==null){
monthlyTab.setVisibility(View.GONE);
if(campaign.amounts.oneTime!=null){
onceTab.setSelected(true);
currentTab=R.id.once;
frequency=DonationFrequency.ONCE;
}else if(campaign.amounts.yearly!=null){
yearlyTab.setSelected(true);
currentTab=R.id.yearly;
frequency=DonationFrequency.YEARLY;
}else{
Toast.makeText(context, "Amounts object is empty", Toast.LENGTH_SHORT).show();
dismiss();
return;
}
}else{
monthlyTab.setSelected(true);
currentTab=R.id.monthly;
}
View tabBarItself=findViewById(R.id.tabbar_inner);
tabBarItself.setOutlineProvider(OutlineProviders.roundedRect(20));
tabBarItself.setClipToOutline(true);
amountField=findViewById(R.id.amount);
List<String> availableCurrencies=campaign.amounts.monthly.keySet().stream().sorted().collect(Collectors.toList());
amountField.setCurrencies(availableCurrencies);
try{
amountField.setSelectedCurrency(campaign.defaultCurrency);
}catch(IllegalArgumentException x){
new M3AlertDialogBuilder(context)
.setTitle(R.string.error)
.setMessage("Default currency "+campaign.defaultCurrency+" not in list of available currencies "+availableCurrencies)
.show();
dismiss();
return;
}
amountField.setChangeListener(new CurrencyAmountInput.ChangeListener(){
@Override
public void onCurrencyChanged(String code){
updateSuggestedAmounts(code);
button.setEnabled(amountField.getAmount()>=getMinimumChargeAmount(code));
updateSuggestedButtonsState();
}
@Override
public void onAmountChanged(long amount){
button.setEnabled(amount>=getMinimumChargeAmount(amountField.getCurrency()));
updateSuggestedButtonsState();
}
});
button=findViewById(R.id.button);
buttonText=findViewById(R.id.button_text);
ViewGroup suggestedAmounts=findViewById(R.id.suggested_amounts);
for(int i=0;i<suggestedAmountButtons.length;i++){
ToggleButton btn=new ToggleButton(context);
btn.setBackgroundResource(R.drawable.bg_filter_chip);
btn.setTextAppearance(R.style.m3_label_large);
btn.setTextColor(context.getResources().getColorStateList(R.color.filter_chip_text, context.getTheme()));
btn.setMinWidth(V.dp(64));
btn.setMinimumWidth(0);
btn.setPadding(0, 0, 0, 0);
btn.setStateListAnimator(null);
btn.setTextOff(null);
btn.setTextOn(null);
btn.setOnClickListener(this::onSuggestedAmountClick);
btn.setTag(i);
btn.setSingleLine();
suggestedAmountButtons[i]=btn;
suggestedAmounts.addView(btn);
}
updateSuggestedAmounts(campaign.defaultCurrency);
button.setEnabled(false);
buttonText.setText(campaign.donationButtonText);
button.setOnClickListener(v->openWebView());
Arrays.stream(getCurrentSuggestedAmounts(campaign.defaultCurrency)).min().ifPresent(amountField::setAmount);
}
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Window window=getWindow();
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
private void onTabClick(View v){
if(v.getId()==currentTab)
return;
findViewById(currentTab).setSelected(false);
v.setSelected(true);
currentTab=v.getId();
if(currentTab==R.id.once)
frequency=DonationFrequency.ONCE;
else if(currentTab==R.id.monthly)
frequency=DonationFrequency.MONTHLY;
else if(currentTab==R.id.yearly)
frequency=DonationFrequency.YEARLY;
updateSuggestedAmounts(amountField.getCurrency());
}
private long[] getCurrentSuggestedAmounts(String currency){
long[] amounts=(switch(frequency){
case ONCE -> campaign.amounts.oneTime;
case MONTHLY -> campaign.amounts.monthly;
case YEARLY -> campaign.amounts.yearly;
}).get(currency);
if(amounts==null){
amounts=new long[0];
}
return amounts;
}
private void updateSuggestedAmounts(String currency){
NumberFormat format=NumberFormat.getCurrencyInstance();
try{
format.setCurrency(Currency.getInstance(currency));
}catch(IllegalArgumentException ignore){}
int defaultFractionDigits=format.getMinimumFractionDigits();
long[] amounts=getCurrentSuggestedAmounts(currency);
for(int i=0;i<suggestedAmountButtons.length;i++){
ToggleButton btn=suggestedAmountButtons[i];
if(i>=amounts.length){
btn.setVisibility(View.GONE);
continue;
}
btn.setVisibility(View.VISIBLE);
long amount=amounts[i];
format.setMinimumFractionDigits(amount%100==0 ? 0 : defaultFractionDigits);
btn.setText(format.format(amount/100.0));
}
updateSuggestedButtonsState();
}
private void onSuggestedAmountClick(View v){
int index=(int) v.getTag();
long[] amounts=getCurrentSuggestedAmounts(amountField.getCurrency());
amountField.setAmount(amounts[index]);
}
private void updateSuggestedButtonsState(){
long amount=amountField.getAmount();
long[] amounts=getCurrentSuggestedAmounts(amountField.getCurrency());
for(int i=0;i<Math.min(amounts.length, suggestedAmountButtons.length);i++){
ToggleButton btn=suggestedAmountButtons[i];
btn.setChecked(amounts[i]==amount);
}
}
private void openWebView(){
Uri.Builder builder=Uri.parse(campaign.donationUrl).buildUpon();
builder.appendQueryParameter("locale", Locale.getDefault().toLanguageTag().replace('-', '_'))
.appendQueryParameter("platform", "android")
.appendQueryParameter("currency", amountField.getCurrency())
.appendQueryParameter("amount", String.valueOf(amountField.getAmount()))
.appendQueryParameter("source", "campaign")
.appendQueryParameter("campaign_id", campaign.id)
.appendQueryParameter("frequency", switch(frequency){
case ONCE -> "one_time";
case MONTHLY -> "monthly";
case YEARLY -> "yearly";
})
.appendQueryParameter("success_callback_url", DonationWebViewFragment.SUCCESS_URL)
.appendQueryParameter("cancel_callback_url", DonationWebViewFragment.CANCEL_URL)
.appendQueryParameter("failure_callback_url", DonationWebViewFragment.FAILURE_URL);
Bundle args=new Bundle();
args.putString("url", builder.build().toString());
args.putString("account", accountID);
args.putString("campaignID", campaign.id);
args.putString("successPostText", campaign.donationSuccessPost);
args.putBoolean("_can_go_back", true);
startCallback.accept(new Intent(activity, DonationFragmentActivity.class).putExtra("fragmentArgs", args));
}
private static long getMinimumChargeAmount(String currency){
// https://docs.stripe.com/currencies#minimum-and-maximum-charge-amounts
// values are in cents
return switch(currency){
case "USD" -> 50;
case "AED" -> 2_00;
case "AUD" -> 50;
case "BGN" -> 1_00;
case "BRL" -> 50;
case "CAD" -> 50;
case "CHF" -> 50;
case "CZK" -> 15_00;
case "DKK" -> 2_50;
case "EUR" -> 50;
case "GBP" -> 30;
case "HKD" -> 4_00;
case "HUF" -> 175_00;
case "INR" -> 50;
case "JPY" -> 50_00;
case "MXN" -> 10_00;
case "MYR" -> 2_00;
case "NOK" -> 3_00;
case "NZD" -> 50;
case "PLN" -> 2_00;
case "RON" -> 2_00;
case "SEK" -> 3_00;
case "SGD" -> 50;
case "THB" -> 10_00;
default -> 50;
};
}
private enum DonationFrequency{
ONCE,
MONTHLY,
YEARLY
}
public static class SuggestedAmountsLayout extends ViewGroup implements CustomViewHelper{
private int visibleChildCount;
private static final int H_GAP=24;
private static final int V_GAP=8;
private static final int ROW_HEIGHT=32;
public SuggestedAmountsLayout(Context context){
this(context, null);
}
public SuggestedAmountsLayout(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public SuggestedAmountsLayout(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
visibleChildCount=0;
for(int i=0;i<getChildCount();i++){
View child=getChildAt(i);
if(child.getVisibility()==GONE)
continue;
visibleChildCount++;
}
int width=MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width, visibleChildCount>4 ? dp(ROW_HEIGHT*2+V_GAP) : dp(ROW_HEIGHT));
int buttonsPerRow=visibleChildCount>4 ? 3 : visibleChildCount;
int buttonWidth=(width-dp(H_GAP)*(buttonsPerRow-1))/buttonsPerRow;
for(int i=0;i<getChildCount();i++){
View child=getChildAt(i);
if(child.getVisibility()==GONE)
continue;
child.measure(buttonWidth | MeasureSpec.EXACTLY, dp(ROW_HEIGHT) | MeasureSpec.EXACTLY);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b){
int width=r-l;
int buttonsPerRow=visibleChildCount>4 ? 3 : visibleChildCount;
int buttonWidth=(width-dp(H_GAP)*(buttonsPerRow-1))/buttonsPerRow;
for(int i=0;i<getChildCount();i++){
View child=getChildAt(i);
if(child.getVisibility()==GONE)
continue;
int column=i%buttonsPerRow;
int row=i/buttonsPerRow;
int left=(buttonWidth+dp(H_GAP))*column;
int top=dp(ROW_HEIGHT+V_GAP)*row;
child.layout(left, top, left+buttonWidth, top+dp(ROW_HEIGHT));
}
}
}
}

View File

@@ -0,0 +1,40 @@
package org.joinmastodon.android.ui.sheets;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.ui.utils.UiUtils;
import androidx.annotation.NonNull;
import me.grishka.appkit.Nav;
import me.grishka.appkit.views.BottomSheet;
public class DonationSuccessfulSheet extends BottomSheet{
public DonationSuccessfulSheet(@NonNull Context context, @NonNull String accountID, String postText){
super(context);
View content=context.getSystemService(LayoutInflater.class).inflate(R.layout.sheet_donation_success, null);
setContentView(content);
setNavigationBarBackground(new ColorDrawable(UiUtils.alphaBlendColors(UiUtils.getThemeColor(context, R.attr.colorM3Surface),
UiUtils.getThemeColor(context, R.attr.colorM3Primary), 0.05f)), !UiUtils.isDarkTheme());
content.findViewById(R.id.btn_done).setOnClickListener(v->dismiss());
View shareButton=content.findViewById(R.id.btn_share);
if(postText==null){
shareButton.setEnabled(false);
}
shareButton.setOnClickListener(v->{
Bundle args=new Bundle();
args.putString("account", accountID);
args.putString("prefilledText", postText);
Nav.go((Activity) context, ComposeFragment.class, args);
dismiss();
});
}
}

View File

@@ -550,7 +550,7 @@ public class ComposeMediaViewController{
}
public List<String> getAttachmentIDs(){
return attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList());
return attachments.stream().filter(a->a.serverAttachment!=null).map(a->a.serverAttachment.id).collect(Collectors.toList());
}
public List<CreateStatus.Request.MediaAttribute> getAttachmentAttributes(){

View File

@@ -14,6 +14,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Card;
import org.joinmastodon.android.model.viewmodel.CardViewModel;
import org.joinmastodon.android.ui.OutlineProviders;
@@ -86,7 +87,9 @@ public class LinkCardHolder<T extends LinkCardHolder.LinkCardProvider> extends S
}
String cardDomain=HtmlParser.normalizeDomain(Objects.requireNonNull(Uri.parse(card.url).getHost()));
domain.setText(TextUtils.isEmpty(card.providerName) ? cardDomain : card.providerName);
if(card.authorAccount!=null){
String authorName=card.authors!=null && !card.authors.isEmpty() ? card.authors.get(0).name : card.authorName;
if(cardVM.parsedAuthorName!=null){
authorFooter.setVisibility(View.VISIBLE);
authorChip.setVisibility(View.VISIBLE);
authorBefore.setVisibility(View.VISIBLE);
@@ -102,15 +105,15 @@ public class LinkCardHolder<T extends LinkCardHolder.LinkCardProvider> extends S
authorAfter.setVisibility(View.VISIBLE);
authorAfter.setText(after);
}
authorName.setText(cardVM.parsedAuthorName);
this.authorName.setText(cardVM.parsedAuthorName);
authorBefore.setCompoundDrawablesRelative(logoIcon, null, null, null);
}else if(!TextUtils.isEmpty(card.authorName)){
}else if(!TextUtils.isEmpty(authorName)){
authorFooter.setVisibility(View.VISIBLE);
authorBefore.setVisibility(View.VISIBLE);
authorBefore.setCompoundDrawables(null, null, null, null);
authorChip.setVisibility(View.GONE);
authorAfter.setVisibility(View.GONE);
authorBefore.setText(itemView.getContext().getString(R.string.article_by_author, card.authorName));
authorBefore.setText(itemView.getContext().getString(R.string.article_by_author, authorName));
}else{
authorFooter.setVisibility(View.GONE);
}
@@ -186,7 +189,7 @@ public class LinkCardHolder<T extends LinkCardHolder.LinkCardProvider> extends S
private void onAuthorChipClick(View v){
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("profileAccount", Parcels.wrap(item.getCard().card.authorAccount));
args.putParcelable("profileAccount", Parcels.wrap(item.getCard().getAuthorAccount()));
Nav.go(activity, ProfileFragment.class, args);
}

View File

@@ -0,0 +1,340 @@
package org.joinmastodon.android.ui.views;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.text.style.ReplacementSpan;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Currency;
import java.util.List;
import java.util.stream.Collectors;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import me.grishka.appkit.utils.CustomViewHelper;
public class CurrencyAmountInput extends LinearLayout implements CustomViewHelper{
private ActualEditText edit;
private Button currencyBtn;
private List<CurrencyInfo> currencies;
private CurrencyInfo currentCurrency;
private boolean spanAdded;
private CurrencySymbolSpan symbolSpan;
private boolean symbolBeforeAmount;
private ChangeListener changeListener;
private long lastAmount=0;
private NumberFormat numberFormat=NumberFormat.getNumberInstance();
private boolean allowSymbolToBeDeleted;
public CurrencyAmountInput(Context context){
this(context, null);
}
public CurrencyAmountInput(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public CurrencyAmountInput(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
setForeground(getResources().getDrawable(R.drawable.fg_currency_input, context.getTheme()));
setAddStatesFromChildren(true);
if(!isInEditMode())
setOutlineProvider(OutlineProviders.roundedRect(8));
setClipToOutline(true);
currencyBtn=new Button(context);
currencyBtn.setTextAppearance(R.style.m3_label_large);
currencyBtn.setSingleLine();
currencyBtn.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3OnSurfaceVariant));
int pad=dp(12);
currencyBtn.setPadding(pad, 0, pad, 0);
currencyBtn.setBackgroundColor(UiUtils.getThemeColor(context, R.attr.colorM3SurfaceVariant));
currencyBtn.setMinimumWidth(0);
currencyBtn.setMinWidth(0);
currencyBtn.setOnClickListener(v->showCurrencySelector());
currencyBtn.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_unfold_more_wght600_15pt_8x20px, 0, 0, 0);
currencyBtn.setCompoundDrawableTintList(currencyBtn.getTextColors());
currencyBtn.setCompoundDrawablePadding(dp(4));
addView(currencyBtn, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT));
edit=new ActualEditText(context);
edit.setBackgroundColor(UiUtils.getThemeColor(context, R.attr.colorM3Surface));
pad=dp(16);
edit.setPadding(pad, 0, pad, 0);
edit.setSingleLine();
edit.setTextAppearance(R.style.m3_title_large);
edit.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3OnSurface));
edit.setGravity(Gravity.END |Gravity.CENTER_VERTICAL);
edit.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
InputFilter[] filters=edit.getText().getFilters();
for(int i=0;i<filters.length;i++){
if(filters[i] instanceof DigitsKeyListener){
filters[i]=new FormattingFriendlyDigitsKeyListener();
edit.getText().setFilters(filters);
break;
}
}
addView(edit, new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
symbolSpan=new CurrencySymbolSpan(edit.getPaint());
NumberFormat format=NumberFormat.getInstance();
String one=format.format(1);
format=NumberFormat.getCurrencyInstance();
format.setCurrency(Currency.getInstance("USD"));
symbolBeforeAmount=format.format(1).indexOf(one)>0;
edit.addTextChangedListener(new TextWatcher(){
private boolean ignore;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after){
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count){
}
@Override
public void afterTextChanged(Editable e){
if(ignore)
return;
ignore=true;
if(e.length()>0 && !spanAdded){
SpannableString ss=new SpannableString(" ");
ss.setSpan(symbolSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
if(symbolBeforeAmount)
e.insert(0, ss);
else
e.append(ss);
spanAdded=true;
}else if(spanAdded && e.length()<=1){
spanAdded=false;
if(e.length()>0){
allowSymbolToBeDeleted=true;
e.clear();
allowSymbolToBeDeleted=false;
}
}
ignore=false;
updateAmount();
}
});
}
public void setCurrencies(List<String> currencies){
this.currencies=currencies.stream().map(CurrencyInfo::new).collect(Collectors.toList());
}
public void setSelectedCurrency(String code){
CurrencyInfo info=null;
for(CurrencyInfo c:currencies){
if(c.code.equals(code)){
info=c;
break;
}
}
if(info==null)
throw new IllegalArgumentException();
setCurrency(info);
}
private void setCurrency(CurrencyInfo info){
currencyBtn.setText(info.code);
currentCurrency=info;
edit.invalidate();
if(changeListener!=null)
changeListener.onCurrencyChanged(info.code);
}
private void showCurrencySelector(){
ArrayAdapter<CurrencyInfo> adapter=new ArrayAdapter<>(getContext(), R.layout.item_alert_single_choice_2lines_but_different, R.id.text, currencies){
@Override
public boolean hasStableIds(){
return true;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent){
View view=super.getView(position, convertView, parent);
TextView subtitle=view.findViewById(R.id.subtitle);
CurrencyInfo item=getItem(position);
if(item.jCurrency==null || item.jCurrency.getDisplayName().equals(item.code)){
subtitle.setVisibility(View.GONE);
}else{
subtitle.setVisibility(View.VISIBLE);
subtitle.setText(item.jCurrency.getDisplayName());
}
return view;
}
};
new M3AlertDialogBuilder(getContext())
.setTitle(R.string.currency)
.setSingleChoiceItems(adapter, currencies.indexOf(currentCurrency), (dlg, item)->{
setCurrency(currencies.get(item));
dlg.dismiss();
})
.show();
}
public void setChangeListener(ChangeListener changeListener){
this.changeListener=changeListener;
}
private void updateAmount(){
long newAmount;
try{
Number n=numberFormat.parse(edit.getText().toString().trim());
if(n instanceof Long l){
newAmount=l*100L;
}else if(n instanceof Double d){
newAmount=(long)(d*100);
}else{
newAmount=0;
}
}catch(ParseException x){
newAmount=0;
}
if(newAmount!=lastAmount){
lastAmount=newAmount;
if(changeListener!=null)
changeListener.onAmountChanged(lastAmount);
}
}
public long getAmount(){
return lastAmount;
}
public String getCurrency(){
return currentCurrency.code;
}
@SuppressLint("DefaultLocale")
public void setAmount(long amount){
String value;
if(amount%100==0)
value=String.valueOf(amount/100);
else
value=String.format("%.2f", amount/100.0);
int start=spanAdded ? 1 : 0;
edit.getText().replace(start, edit.length(), value);
}
private class ActualEditText extends EditText{
public ActualEditText(Context context){
super(context);
setClipToPadding(false);
}
@Override
protected void onSelectionChanged(int selStart, int selEnd){
super.onSelectionChanged(selStart, selEnd);
// Adjust the selection to prevent the symbol span being selected
if(spanAdded){
int newSelStart=symbolBeforeAmount ? Math.max(selStart, 1) : Math.min(selStart, length()-1);
int newSelEnd=symbolBeforeAmount ? Math.max(selEnd, 1) : Math.min(selEnd, length()-1);
if(newSelStart!=selStart || newSelEnd!=selEnd){
setSelection(newSelStart, newSelEnd);
}
}
}
}
private static class CurrencyInfo{
public String code;
public String symbol;
public Currency jCurrency;
public CurrencyInfo(String code){
this.code=code;
try{
jCurrency=Currency.getInstance(code);
symbol=jCurrency.getSymbol();
}catch(IllegalArgumentException x){
symbol=code;
}
}
@NonNull
@Override
public String toString(){
return code;
}
}
private class CurrencySymbolSpan extends ReplacementSpan{
private Paint paint;
public CurrencySymbolSpan(Paint paint){
this.paint=new Paint(paint);
this.paint.setTextSize(paint.getTextSize()*0.66f);
}
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm){
return Math.round(this.paint.measureText(currentCurrency.symbol))+dp(2);
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint){
this.paint.setColor(paint.getColor());
this.paint.setAlpha(77);
if(!symbolBeforeAmount)
x+=dp(2);
canvas.drawText(currentCurrency.symbol, x, top+dp(1.5f)-this.paint.ascent(), this.paint);
}
}
private class FormattingFriendlyDigitsKeyListener extends DigitsKeyListener{
public FormattingFriendlyDigitsKeyListener(){
super(false, true);
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend){
// Allow the currency symbol to be inserted (always done as a separate insertion operation)
if(source instanceof Spannable s && s.getSpans(start, end, CurrencySymbolSpan.class).length>0){
return source;
}
// Don't allow the currency symbol to be deleted
if(!allowSymbolToBeDeleted && end-start<dend-dstart && dest.getSpans(dstart, dend, CurrencySymbolSpan.class).length>0){
return dest.subSequence(dstart, dend);
}
return super.filter(source, start, end, dest, dstart, dend);
}
}
public interface ChangeListener{
void onCurrencyChanged(String code);
void onAmountChanged(long amount);
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:interpolator="@interpolator/cubic_bezier_default"
android:shareInterpolator="true"
>
<alpha
android:fromAlpha="0"
android:toAlpha="1" />
<translate
android:fromXDelta="@integer/hundred_dp"
android:toXDelta="0"/>
</set>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:interpolator="@interpolator/cubic_bezier_default"
android:shareInterpolator="true"
>
<alpha
android:fromAlpha="1"
android:toAlpha="0" />
<translate
android:fromXDelta="0"
android:toXDelta="@integer/hundred_dp"/>
</set>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300">
</set>

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="@color/masterialDark_secondaryContainer"/>
</item>
<item android:height="0dp">
<layer-list>
<item android:gravity="center_vertical|end">
<bitmap android:src="@drawable/scribble" android:alpha="0.08" android:autoMirrored="true"/>
</item>
</layer-list>
</item>
</layer-list>

View File

@@ -1,5 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<ripple android:color="@color/m3_on_secondary_container_overlay">
<item>
<shape>
<corners android:radius="8dp"/>
<solid android:color="?colorM3SecondaryContainer"/>
</shape>
</item>
</ripple>
</item>
<item android:state_selected="true">
<ripple android:color="@color/m3_on_secondary_container_overlay">
<item>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<shape>
<corners android:radius="8dp"/>
<stroke android:color="?colorM3Primary" android:width="1dp"/>
</shape>
</item>
<item>
<shape>
<corners android:radius="8dp"/>
<stroke android:color="?colorM3OutlineVariant" android:width="1dp"/>
</shape>
</item>
</selector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="@android:color/white"
android:pathData="M15,10.875V9.125H18.333V10.875ZM16,16.667 L13.333,14.667 14.375,13.25 17.042,15.25ZM14.396,6.729 L13.333,5.333 16,3.333 17.062,4.729ZM4.167,15.833V12.5H3.417Q2.729,12.5 2.198,12.052Q1.667,11.604 1.667,10.917V9.083Q1.667,8.396 2.198,7.948Q2.729,7.5 3.417,7.5H6.667L10.833,5V15L6.667,12.5H5.917V15.833ZM11.708,12.792V7.208Q12.271,7.708 12.615,8.427Q12.958,9.146 12.958,10Q12.958,10.854 12.615,11.573Q12.271,12.292 11.708,12.792ZM3.417,9.25Q3.417,9.25 3.417,9.25Q3.417,9.25 3.417,9.25V10.75Q3.417,10.75 3.417,10.75Q3.417,10.75 3.417,10.75H7.208L9.083,11.917V8.083L7.208,9.25ZM6.25,10Q6.25,10 6.25,10Q6.25,10 6.25,10Q6.25,10 6.25,10Q6.25,10 6.25,10Z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@drawable/ic_baseline_check_18"/>
<item android:drawable="@drawable/ic_favorite_18px"/>
</selector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="@android:color/white"
android:pathData="M10,17 L8.958,16.062Q6.875,14.208 5.521,12.885Q4.167,11.562 3.385,10.531Q2.604,9.5 2.302,8.646Q2,7.792 2,6.896Q2,5.042 3.271,3.771Q4.542,2.5 6.396,2.5Q7.417,2.5 8.375,2.938Q9.333,3.375 10,4.167Q10.667,3.375 11.625,2.938Q12.583,2.5 13.604,2.5Q15.458,2.5 16.729,3.771Q18,5.042 18,6.896Q18,7.792 17.708,8.625Q17.417,9.458 16.635,10.479Q15.854,11.5 14.49,12.844Q13.125,14.188 11,16.104ZM10,14.979Q11.938,13.25 13.188,12.031Q14.438,10.812 15.177,9.906Q15.917,9 16.208,8.292Q16.5,7.583 16.5,6.896Q16.5,5.667 15.667,4.833Q14.833,4 13.604,4Q12.875,4 12.24,4.302Q11.604,4.604 11.146,5.146L10.417,6H9.583L8.854,5.146Q8.396,4.604 7.74,4.302Q7.083,4 6.396,4Q5.167,4 4.333,4.833Q3.5,5.667 3.5,6.896Q3.5,7.583 3.771,8.26Q4.042,8.938 4.76,9.833Q5.479,10.729 6.74,11.958Q8,13.188 10,14.979ZM10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Q10,9.479 10,9.479Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M482,640L622,500Q639,483 644,458.5Q649,434 639,411Q629,388 609,374Q589,360 564,360Q539,360 519,375.5Q499,391 482,408Q464,391 444.5,375.5Q425,360 400,360Q375,360 354.5,373.5Q334,387 324,410Q314,433 319.5,457.5Q325,482 342,500L482,640ZM370,880L354,752Q341,747 329.5,740Q318,733 307,725L188,775L78,585L181,507Q180,500 180,493.5Q180,487 180,480Q180,473 180,466.5Q180,460 181,453L78,375L188,185L307,235Q318,227 330,220Q342,213 354,208L370,80L590,80L606,208Q619,213 630.5,220Q642,227 653,235L772,185L882,375L779,453Q780,460 780,466.5Q780,473 780,480Q780,487 780,493.5Q780,500 778,507L881,585L771,775L653,725Q642,733 630,740Q618,747 606,752L590,880L370,880ZM440,800L519,800L533,694Q564,686 590.5,670.5Q617,655 639,633L738,674L777,606L691,541Q696,527 698,511.5Q700,496 700,480Q700,464 698,448.5Q696,433 691,419L777,354L738,286L639,328Q617,305 590.5,289.5Q564,274 533,266L520,160L441,160L427,266Q396,274 369.5,289.5Q343,305 321,327L222,286L183,354L269,418Q264,433 262,448Q260,463 260,480Q260,496 262,511Q264,526 269,541L183,606L222,674L321,632Q343,655 369.5,670.5Q396,686 427,694L440,800ZM480,480L480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480L480,480L480,480Z"/>
</vector>

View File

@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="8dp"
android:height="20dp"
android:viewportWidth="8"
android:viewportHeight="20">
<group android:translateX="-6" android:scaleX="0.75" android:scaleY="0.75" android:pivotX="10" android:pivotY="10">
<path
android:fillColor="@android:color/white"
android:pathData="M10,17.375 L6.208,13.583 7.646,12.167 10,14.5 12.354,12.167 13.792,13.583ZM7.646,7.812 L6.208,6.375 10,2.583 13.792,6.375 12.354,7.812 10,5.458Z" />
</group>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="@android:color/white"
android:pathData="M13.292,10.917Q11.354,9.146 9.812,7.521Q8.271,5.896 8.271,4.458Q8.271,3.292 9.083,2.479Q9.896,1.667 11.062,1.667Q11.729,1.667 12.312,1.938Q12.896,2.208 13.292,2.667Q13.688,2.208 14.271,1.938Q14.854,1.667 15.521,1.667Q16.688,1.667 17.5,2.479Q18.312,3.292 18.312,4.458Q18.312,5.896 16.771,7.521Q15.229,9.146 13.292,10.917ZM13.292,8.542Q14.479,7.396 15.521,6.26Q16.562,5.125 16.562,4.458Q16.562,4.021 16.26,3.719Q15.958,3.417 15.521,3.417Q15.229,3.417 15,3.531Q14.771,3.646 14.625,3.812L13.312,5.375L12,3.812Q11.833,3.646 11.594,3.531Q11.354,3.417 11.062,3.417Q10.625,3.417 10.323,3.719Q10.021,4.021 10.021,4.458Q10.021,5.125 11.062,6.26Q12.104,7.396 13.292,8.542ZM13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979Q13.292,5.979 13.292,5.979ZM11.667,18.75 L5.979,17.167V18.396H0.833V9.042H7.542L12.646,10.938Q13.354,11.208 13.781,11.854Q14.208,12.5 14.208,13.229H15.729Q16.812,13.229 17.573,13.958Q18.333,14.688 18.333,15.771V16.667ZM2.583,16.646H4.229V10.792H2.583ZM11.625,16.938 L16.5,15.396Q16.396,15.208 16.188,15.094Q15.979,14.979 15.729,14.979H11.75Q11.125,14.979 10.646,14.906Q10.167,14.833 9.812,14.708L8.104,14.125L8.646,12.438L10.438,13.042Q10.771,13.146 11.167,13.188Q11.562,13.229 12.479,13.229Q12.479,13 12.344,12.802Q12.208,12.604 12.021,12.542L7.229,10.792H5.979V15.396ZM4.229,13.708ZM12.479,13.229Q12.479,13.229 12.479,13.229Q12.479,13.229 12.479,13.229Q12.479,13.229 12.479,13.229Q12.479,13.229 12.479,13.229Q12.479,13.229 12.479,13.229Q12.479,13.229 12.479,13.229Q12.479,13.229 12.479,13.229Q12.479,13.229 12.479,13.229ZM4.229,13.708ZM5.979,13.708Q5.979,13.708 5.979,13.708Q5.979,13.708 5.979,13.708Q5.979,13.708 5.979,13.708Q5.979,13.708 5.979,13.708Q5.979,13.708 5.979,13.708Q5.979,13.708 5.979,13.708Q5.979,13.708 5.979,13.708Q5.979,13.708 5.979,13.708Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M640,520L474,358Q443,328 421.5,291.5Q400,255 400,212Q400,157 438.5,118.5Q477,80 532,80Q564,80 592,93.5Q620,107 640,130Q660,107 688,93.5Q716,80 748,80Q803,80 841.5,118.5Q880,157 880,212Q880,255 859,291.5Q838,328 807,358L640,520ZM640,408L749,301Q768,282 784,260.5Q800,239 800,212Q800,190 785,175Q770,160 748,160Q734,160 721.5,165.5Q709,171 700,182L640,254L580,182Q571,171 558.5,165.5Q546,160 532,160Q510,160 495,175Q480,190 480,212Q480,239 496,260.5Q512,282 531,301L640,408ZM280,740L558,816L796,742Q791,733 781.5,726.5Q772,720 760,720L558,720Q531,720 515,718Q499,716 482,710L389,679L411,601L492,628Q509,633 532,636Q555,639 600,640L600,640Q600,640 600,640Q600,640 600,640Q600,629 593.5,619Q587,609 578,606L344,520Q344,520 344,520Q344,520 344,520L280,520L280,740ZM40,880L40,440L344,440Q351,440 358,441.5Q365,443 371,445L606,532Q639,544 659.5,574Q680,604 680,640L760,640Q810,640 845,673Q880,706 880,760L880,800L560,900L280,822L280,822L280,880L40,880ZM120,800L200,800L200,520L120,520L120,800ZM640,254L640,254Q640,254 640,254Q640,254 640,254Q640,254 640,254Q640,254 640,254Q640,254 640,254Q640,254 640,254L640,254L640,254Q640,254 640,254Q640,254 640,254Q640,254 640,254Q640,254 640,254Q640,254 640,254Q640,254 640,254L640,254Z"/>
</vector>

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="0.25" android:controlY1="0.1" android:controlX2="0.25" android:controlY2="1"/>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="12dp"
android:paddingStart="16dp"
android:paddingEnd="8dp"
android:gravity="center_vertical"
android:background="@drawable/bg_donation_banner">
<TextView
android:id="@+id/banner_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="@style/m3_body_medium"
android:textColor="@color/masterialDark_onSecondaryContainer"
tools:text="Donation banner text goes here"/>
<ImageButton
android:id="@+id/banner_dismiss"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="?android:actionBarItemBackground"
android:tint="@color/masterialDark_onSecondaryContainer"
android:backgroundTint="@color/masterialDark_onSecondaryContainer"
android:src="@drawable/ic_baseline_close_24"
android:contentDescription="@string/dismiss"/>
</LinearLayout>

View File

@@ -58,5 +58,12 @@
android:text="@string/see_new_posts"/>
</FrameLayout>
<ViewStub
android:id="@+id/donation_banner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout="@layout/donation_banner"/>
</FrameLayout>
</me.grishka.appkit.views.RecursiveSwipeRefreshLayout>

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<org.joinmastodon.android.ui.views.CustomScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_bottom_sheet"
android:outlineProvider="background"
android:elevation="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingHorizontal="16dp">
<View
android:id="@+id/handle"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_bottom_sheet_handle"/>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_body_large"
android:textColor="?colorM3OnSurfaceVariant"
tools:text="By supporting Mastodon, you help sustain a global network that values people over profit. Will you join us today?"/>
<FrameLayout
android:id="@+id/tabbar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="16dp">
<LinearLayout
android:id="@+id/tabbar_inner"
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal"
android:layout_gravity="center"
style="@style/Widget.Mastodon.M3.SegmentedButtonContainer">
<FrameLayout
android:id="@+id/once"
style="@style/Widget.Mastodon.M3.SegmentedButton">
<org.joinmastodon.android.ui.views.CheckIconSelectableTextView
style="@style/Widget.Mastodon.M3.SegmentedButtonText"
android:text="@string/donation_once"/>
</FrameLayout>
<FrameLayout
android:id="@+id/monthly"
style="@style/Widget.Mastodon.M3.SegmentedButton">
<TextView
style="@style/Widget.Mastodon.M3.SegmentedButtonText"
android:drawableStart="@drawable/ic_donation_monthly"
android:drawableTint="?colorM3OnSurface"
android:text="@string/donation_monthly"/>
</FrameLayout>
<FrameLayout
android:id="@+id/yearly"
style="@style/Widget.Mastodon.M3.SegmentedButton">
<org.joinmastodon.android.ui.views.CheckIconSelectableTextView
style="@style/Widget.Mastodon.M3.SegmentedButtonText"
android:text="@string/donation_yearly"/>
</FrameLayout>
</LinearLayout>
</FrameLayout>
<org.joinmastodon.android.ui.views.CurrencyAmountInput
android:id="@+id/amount"
android:layout_width="match_parent"
android:layout_height="52dp"
android:layout_marginTop="16dp"/>
<view class="org.joinmastodon.android.ui.sheets.DonationSheet$SuggestedAmountsLayout"
android:id="@+id/suggested_amounts"
android:layout_width="match_parent"
android:layout_height="32dp"
android:layout_marginTop="8dp"/>
<FrameLayout
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="28dp"
style="@style/Widget.Mastodon.M3.Button.Filled">
<TextView
android:id="@+id/button_text"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:drawableStart="@drawable/ic_volunteer_activism_20px"
style="@style/Widget.Mastodon.M3.Button.Filled"
android:background="@null"
android:padding="0dp"
android:drawablePadding="8dp"
android:drawableTint="@color/button_text_m3_filled"
android:clickable="false"
android:focusable="false"
android:duplicateParentState="true"
android:minWidth="0dp"
tools:text="Donate"/>
</FrameLayout>
</LinearLayout>
</org.joinmastodon.android.ui.views.CustomScrollView>

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<org.joinmastodon.android.ui.views.CustomScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/bg_bottom_sheet"
android:outlineProvider="background"
android:elevation="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingHorizontal="16dp">
<View
android:id="@+id/handle"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_bottom_sheet_handle"/>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_headline_medium"
android:textColor="?colorM3OnSurface"
android:gravity="center"
android:text="@string/donation_success_title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textAppearance="@style/m3_body_large"
android:gravity="center"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/donation_success_subtitle"/>
<org.joinmastodon.android.ui.views.FixedAspectRatioImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:src="@drawable/donation_successful_art"
app:aspectRatio="1.777777"/>
<FrameLayout
android:id="@+id/btn_share"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="16dp"
style="@style/Widget.Mastodon.M3.Button.Filled">
<TextView
android:id="@+id/button_text"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:drawableStart="@drawable/ic_campaign_20px"
style="@style/Widget.Mastodon.M3.Button.Filled"
android:background="@null"
android:padding="0dp"
android:drawablePadding="8dp"
android:drawableTint="@color/button_text_m3_filled"
android:clickable="false"
android:focusable="false"
android:duplicateParentState="true"
android:minWidth="0dp"
android:text="@string/donation_success_share"/>
</FrameLayout>
<Button
android:id="@+id/btn_done"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="16dp"
style="@style/Widget.Mastodon.M3.Button.Outlined"
android:text="@string/done"/>
</LinearLayout>
</org.joinmastodon.android.ui.views.CustomScrollView>

View File

@@ -707,6 +707,12 @@
<string name="visibility_subtitle_unlisted">سروصدای الگوریتمی کم‌تر</string>
<string name="visibility_subtitle_followers">تنها پی‌گیرندگانتان</string>
<string name="visibility_subtitle_private">هرکسی که در فرسته نام برده شده</string>
<string name="view_boosts">مشاهده تقویت‌ّها</string>
<string name="view_favorites">دیدن برگزیده‌ها</string>
<string name="undo_reblog">لغو تقویت</string>
<string name="undo_favorite">لغو برگزیدگی</string>
<plurals name="x_new_notifications">
<item quantity="one">%,d اعلان جدید</item>
<item quantity="other">%,d اعلان جدید</item>
</plurals>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="hundred_dp">150</integer>
</resources>

View File

@@ -307,6 +307,7 @@
<string name="instance_signup_closed">Ez a kiszolgáló nem fogad új regisztrációkat.</string>
<string name="text_copied">A szöveg a vágólapra másolva</string>
<string name="add_bookmark">Könyvjelzőzés</string>
<string name="remove_bookmark">Könyvjelző eltávolítása</string>
<string name="bookmarks">Könyvjelzők</string>
<string name="your_favorites">Kedvencek</string>
<string name="login_title">Üdv újra itt</string>

View File

@@ -9,6 +9,7 @@
<string name="preparing_auth">Պատրաստում ենք ավտոենտիֆիկացիայի…</string>
<string name="finishing_auth">Ավարտում ենք ավտոենտիֆիկացիան…</string>
<string name="user_boosted">%s-ը տարածել է</string>
<string name="in_reply_to">ի պատասխան %s-ին</string>
<string name="notifications">Ծանուցումներ</string>
<string name="user_followed_you">%s սկսեց հետեւել ձեզ</string>
<string name="user_sent_follow_request">%s հետեւելու հարցում է ուղարկել</string>
@@ -99,6 +100,7 @@
<string name="confirm_delete_title">Ջնջել գրառումը</string>
<string name="confirm_delete">Վստա՞հ եք, որ ուզում եք ջնջել այս գրառումը։</string>
<string name="deleting">Ջնջում…</string>
<string name="notification_channel_audio_player">Ձայնի նվագարկում</string>
<string name="play">Նվագարկել</string>
<string name="pause">Դադար տալ</string>
<string name="log_out">Ելք</string>
@@ -136,6 +138,7 @@
<string name="mute_user_explain">Դուք չեք տեսնի նրա գրառումները։ Նա դեռ կարող է ձեզ հետևել և տեսնել ձեր գրառումները և չի իմանա, որ խլեցված է։</string>
<string name="block_user_explain">Դուք չեք տեսնի նրա գրառումները։ Նա չի կարող ձեզ հետևել կամ տեսնել ձեր գրառումները։ Նա կիմանա, որ արգելափակված է։</string>
<string name="report_personal_title">Չե՞ք ուզում սա տեսնել։</string>
<string name="report_personal_subtitle">Ահա ձեր տարբերակները` Մաստոդոնում ձեզ երևացող նյութերը կառավարելու համար.</string>
<string name="back">Ետ</string>
<string name="search_communities">Սպասարկչի անուն կամ հասցե</string>
<string name="instance_rules_title">Սպասարկչի կանոնները</string>
@@ -159,6 +162,8 @@
<string name="save">Պահպանել</string>
<string name="add_alt_text">Ավելացնել բացատրություն</string>
<string name="visibility_public">Հրապարակային</string>
<string name="visibility_followers_only">Հետևորդներ</string>
<string name="visibility_private">Նշված մարդիկ</string>
<string name="recent_searches">Վերջին</string>
<string name="skip">Բաց թողնել</string>
<string name="notification_type_follow">Նոր հետևորդներ</string>
@@ -168,6 +173,10 @@
<string name="notification_type_poll">Հարցումներ</string>
<string name="choose_account">Ընտրել հաշիվը</string>
<string name="err_not_logged_in">Սկզբից մուտք գործեք Մաստոդոն</string>
<plurals name="cant_add_more_than_x_attachments">
<item quantity="one">Չի կարելի կցել %d-ից ավել մեդիա</item>
<item quantity="other">Չի կարելի կցել %d-ից ավել մեդիա</item>
</plurals>
<string name="media_attachment_unsupported_type">%s ֆայլը անհամատեղելի տեսակի է</string>
<string name="media_attachment_too_big">%1$s ֆայլի չափսը գերազանցում է %2$s ՄԲ առավելագույն շեմը</string>
<string name="settings_theme">Տեսք</string>
@@ -291,7 +300,9 @@
<string name="login_subtitle">Մուտք գործեք այն սերվերի միջոցով, որտեղ ստեղծել եք ձեր հաշիվը։</string>
<string name="server_url">Սերվերի հասցե</string>
<string name="server_filter_any_language">Որևե լեզու</string>
<string name="server_filter_instant_signup">Գրանցում միանգամից</string>
<string name="server_filter_manual_review">Հայտերի ստուգում</string>
<string name="server_filter_any_signup_speed">Գրանցման որեւէ արագություն</string>
<string name="server_filter_region_europe">Եվրոպա</string>
<string name="server_filter_region_north_america">Հյուսիսային Ամերիկա</string>
<string name="server_filter_region_south_america">Հարավային Ամերիկա</string>
@@ -311,6 +322,7 @@
<string name="server_policy_disagree">Համաձայն չեմ %s-ի հետ</string>
<string name="profile_bio">Կենսագրություն</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<string name="sending_follows">Հետեւում...</string>
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
<string name="signup_email_domain_blocked">%1$s-ը %2$s-ից գրանցումներ չի ընդունում։ Փորձեք ուրիշը կամ &lt;a&gt;ընտրեք ուրիշ սերվեր&lt;/a&gt;։</string>
<string name="spoiler_show">Ցույց տալ</string>
@@ -335,6 +347,7 @@
<string name="opening_link">Հղումը բացվում է...</string>
<string name="link_not_supported">Հղումը համատեղելի չէ ծրագրի հետ</string>
<string name="log_out_all_accounts">Ելք բոլոր հաշիվներից</string>
<string name="confirm_log_out_all_accounts">Ելք բոլոր հաշիվների՞ց</string>
<string name="retry">Կրկին</string>
<string name="post_failed">Չհաջողվեց ուղարկել գրառումը</string>
<!-- %s is formatted file size ("467 KB image") -->
@@ -380,6 +393,8 @@
<string name="reported">Բողոքարկված</string>
<string name="report_unfollow_explanation">Նրա գրառումները այլևս չտեսնելու համար ապահետեւեք նրան։</string>
<string name="muted_user">%s-ը լռեցվել է</string>
<string name="report_sent_already_blocked">Դուք արդեն արգելափակել եք այս օգտատիրոջը։ Այլ գործողությունների կարիք չկա` մինչ մենք դիտարկում ենք ձեր զեկույցը։</string>
<string name="report_personal_already_blocked">Դուք արդեն արգելափակել եք այս օգտատիրոջը, և այլ գործողությունների կարիք չկա։\n\nՇնորհակալությու՜ն, որ օգնում եք պահել Մաստոդոնի ապահովությունը բոլորի համար։</string>
<string name="blocked_user">%s-ը արգելափակվել է</string>
<string name="mark_all_notifications_read">Նշել բոլորը` որպես ընթերցված</string>
<string name="settings_display">Տեսք</string>
@@ -389,14 +404,16 @@
<string name="about_app">%s-ի մասին</string>
<string name="default_post_language">Գրառման լռելյայն լեզու</string>
<string name="settings_alt_text_reminders">Ավելացնել բացատրության մասին հիշեցումներ</string>
<string name="settings_confirm_unfollow">Հարցնել` մեկին ապահետեւելուց առաջ</string>
<string name="settings_confirm_boost">Հարցնել տարածելուց առաջ</string>
<string name="settings_confirm_delete_post">Հարցնել գրառում ջնջելուց առաջ</string>
<string name="pause_all_notifications">Դադարեցնել բոլորը</string>
<string name="pause_notifications_off">Անջատ</string>
<string name="notifications_policy_anyone">Որեւե մեկը</string>
<string name="notifications_policy_followed">Մարդիկ, որոնք ձեզ հետեւում են</string>
<string name="notifications_policy_follower">Մարդիկ, որոնց դուք հետեւում եք</string>
<string name="notifications_policy_no_one">Ոչ ոք</string>
<string name="notifications_policy_anyone">Որեւէ մեկից</string>
<string name="notifications_policy_followed">Մարդկանցից, որոնք ձեզ հետեւում են</string>
<string name="notifications_policy_follower">Մարդկանցից, որոնց դուք հետեւում եք</string>
<string name="notifications_policy_no_one">Ոչ մեկից</string>
<string name="settings_notifications_policy">Ստանալ ծանուցումներ...</string>
<string name="pause_all_notifications_title">Դադարեցնել բոլոր ծանուցումները</string>
<plurals name="x_weeks">
<item quantity="one">%d շաբաթ</item>

View File

@@ -1,45 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="log_in">Acceder</string>
<string name="log_in">Aperir session</string>
<string name="next">Sequente</string>
<string name="loading_instance">Recuperation de info de servitor…</string>
<string name="error">Error</string>
<string name="not_a_mastodon_instance">%s non pare esser un servitor de Mastodon.</string>
<string name="ok">OK</string>
<string name="preparing_auth">Preparation pro authentication…</string>
<string name="finishing_auth">Finiente authentication…</string>
<string name="user_boosted">%s promovite</string>
<string name="in_reply_to">respondente a: %s</string>
<string name="finishing_auth">Finalisation del authentication…</string>
<string name="user_boosted">%s ha impulsate</string>
<string name="in_reply_to">in responsa a %s</string>
<string name="notifications">Notificationes</string>
<string name="user_followed_you">%s te seque</string>
<string name="user_sent_follow_request">%s te ha inviate un requesta de sequer</string>
<string name="user_favorited">%s favoriva tu message</string>
<string name="notification_boosted">%s promoveva tu message</string>
<string name="poll_ended">Vider le resultatos de un sondage in que tu votava</string>
<string name="user_sent_follow_request">%s te ha inviate un requesta de sequimento</string>
<string name="user_favorited">%s ha marcate tu message como favorite</string>
<string name="notification_boosted">%s ha impulsate tu message</string>
<string name="poll_ended">Vider le resultatos de un sondage in que tu ha votate</string>
<string name="share_toot_title">Compartir</string>
<string name="settings">Parametros</string>
<string name="publish">Publicar</string>
<string name="discard_draft">Remover le minuta?</string>
<string name="discard">Remover</string>
<string name="discard_draft">Abandonar le version provisori?</string>
<string name="discard">Abandonar</string>
<string name="cancel">Cancellar</string>
<plurals name="followers">
<item quantity="one">sequace</item>
<item quantity="other">sequaces</item>
<item quantity="one">sequitor</item>
<item quantity="other">sequitores</item>
</plurals>
<plurals name="following">
<item quantity="one">sequente</item>
<item quantity="other">sequente</item>
<item quantity="one">sequite</item>
<item quantity="other">sequites</item>
</plurals>
<string name="posts">Messages</string>
<string name="posts_and_replies">Messages e responsas</string>
<string name="media">Medios</string>
<string name="media">Multimedia</string>
<string name="profile_about">A proposito</string>
<string name="button_follow">Sequer</string>
<string name="button_following">Sequente</string>
<string name="edit_profile">Rediger le profilo</string>
<string name="edit_profile">Modificar profilo</string>
<string name="share_user">Compartir profilo via…</string>
<string name="mute_user">Silentiar %s</string>
<string name="unmute_user">Reactivar audio %s</string>
<string name="unmute_user">Non plus silentiar %s</string>
<string name="block_user">Blocar %s</string>
<string name="unblock_user">Disblocar %s</string>
<string name="report_user">Reportar %s</string>
@@ -55,7 +55,7 @@
<string name="field_label">Etiquetta</string>
<string name="field_content">Contento</string>
<string name="saving">Salvante…</string>
<string name="post_from_user">Message ab %s</string>
<string name="post_from_user">Message de %s</string>
<string name="poll_option_hint">Option %d</string>
<plurals name="x_minutes">
<item quantity="one">%d minuta</item>
@@ -99,7 +99,7 @@
<string name="delete">Deler</string>
<string name="confirm_delete_title">Deler message</string>
<string name="confirm_delete">Es tu secur que tu vole deler iste message?</string>
<string name="deleting">Delente</string>
<string name="deleting">Deletion in curso</string>
<string name="notification_channel_audio_player">Reproduction audio</string>
<string name="play">Reproducer</string>
<string name="pause">Pausar</string>
@@ -116,139 +116,139 @@
<item quantity="other">%d personas parla</item>
</plurals>
<string name="report_title">Reportar %s</string>
<string name="report_choose_reason">Que ha il que non va con iste message?</string>
<string name="report_choose_reason_account">Que ha il que non va con %s?</string>
<string name="report_choose_reason_subtitle">Selige le concordantia melior</string>
<string name="report_choose_reason">Qual es le problema con iste message?</string>
<string name="report_choose_reason_account">Qual es le problema con %s?</string>
<string name="report_choose_reason_subtitle">Selige le option plus adequate</string>
<string name="report_reason_personal">Isto non me place</string>
<string name="report_reason_personal_subtitle">Il non es alco que tu vole vider</string>
<string name="report_reason_personal_subtitle">Isto non es qualcosa que on vole vider</string>
<string name="report_reason_spam">Isto es spam</string>
<string name="report_reason_spam_subtitle">Ligamines maligne, false ingagiamento, o responsas repetitive</string>
<string name="report_reason_spam_subtitle">Ligamines malevolente, interaction false, o responsas repetitive</string>
<string name="report_reason_violation">Isto viola le regulas de servitor</string>
<string name="report_reason_violation_subtitle">Tu es conscie que isto viola regulas specific</string>
<string name="report_reason_other">Il es alco de altere</string>
<string name="report_reason_other">Es altere cosa</string>
<string name="report_reason_other_subtitle">Le problema non entra in altere categorias</string>
<string name="report_choose_rule">Qual regulas es violate?</string>
<string name="report_choose_rule_subtitle">Selige tote le responsas appropriate</string>
<string name="report_choose_posts">Existe alcun messages que appoia iste reporto?</string>
<string name="report_choose_posts_subtitle">Selige tote le responsas appropriate</string>
<string name="report_comment_title">Ha il alco de altere que nos deberea saper?</string>
<string name="report_comment_title">Ha il altere cosas que nos deberea saper?</string>
<string name="report_comment_hint">Commentos additional</string>
<string name="sending_report">Inviante un reporto…</string>
<string name="report_sent_title">Gratias pro le reporto, nos lo reguardara.</string>
<string name="report_sent_subtitle">Dum nos lo revide, tu pote prender action contra %s:</string>
<string name="sending_report">Invio del reporto in curso…</string>
<string name="report_sent_title">Gratias pro le reporto, nos investigara isto.</string>
<string name="report_sent_subtitle">Durante que nos revide isto, tu pote prender mesuras contra @%s:</string>
<string name="unfollow_user">Non plus sequer %s</string>
<string name="unfollow">Non plus sequer</string>
<string name="mute_user_explain">Tu non videra lor messages. Illes pote ancora sequer te e vider tu messages e non sapera que illes es silentiate.</string>
<string name="block_user_explain">Tu non videra lor messages. Illes non potera plus vider tu messages o sequer te. Illes potera saper que illes es blocate.</string>
<string name="report_personal_title">Non vole tu vider lo?</string>
<string name="report_personal_subtitle">Ecce tu optiones pro controlar que tu vide sur Mastodon:</string>
<string name="mute_user_explain">Tu non videra le messages de iste persona. Ille pote totevia sequer te e vider tu messages e non sapera de esser silentiate.</string>
<string name="block_user_explain">Tu non videra le messages de iste persona. Ille non potera vider tu messages o sequer te. Ille potera saper de esser blocate.</string>
<string name="report_personal_title">Non vole vider isto?</string>
<string name="report_personal_subtitle">Ecce tu optiones pro controlar lo que tu vide sur Mastodon:</string>
<string name="back">Retro</string>
<string name="search_communities">Nomine de servitor o URL</string>
<string name="search_communities">Nomine o URL del servitor</string>
<string name="instance_rules_title">Regulas del servitor</string>
<string name="instance_rules_subtitle">Continuante, tu concorda con sequer le regulas sequente definite e reinfortiate per le moderatores de %s.</string>
<string name="instance_rules_subtitle">Si tu continua, tu accepta de respectar le regulas sequente, definite e applicate per le moderatores de %s.</string>
<string name="signup_title">Crear un conto</string>
<string name="display_name">Nomine</string>
<string name="username">Nomine de usator</string>
<string name="email">Email</string>
<string name="email">E-mail</string>
<string name="password">Contrasigno</string>
<string name="confirm_password">Confirmar contrasigno</string>
<string name="category_general">General</string>
<string name="confirm_email_title">Verifica tu cassa de ingresso</string>
<string name="confirm_email_title">Consulta tu cassa de entrata</string>
<!-- %s is the email address -->
<string name="confirm_email_subtitle">Tocca le ligamine que nos te inviava pro verificar %s. Nos attendera justo ci.</string>
<string name="confirm_email_didnt_get">Non obteneva tu un ligamine?</string>
<string name="confirm_email_subtitle">Tocca le ligamine que nos te ha inviate pro verificar %s. Nos te attendera hic.</string>
<string name="confirm_email_didnt_get">Necun ligamine recipite?</string>
<string name="resend">Reinviar</string>
<string name="open_email_app">Aperi le app de email</string>
<string name="resent_email">Email de confirmation inviate</string>
<string name="compose_hint">Scribe o colla lo que es in tu mente</string>
<string name="open_email_app">Aperir le app de e-mail</string>
<string name="resent_email">E-mail de confirmation inviate</string>
<string name="compose_hint">Scribe o colla lo que tu ha in mente</string>
<string name="content_warning">Advertimento de contento</string>
<string name="save">Salvar</string>
<string name="add_alt_text">Adder texto alt</string>
<string name="add_alt_text">Adder texto alternative</string>
<string name="visibility_public">Public</string>
<string name="visibility_followers_only">Sequaces</string>
<string name="visibility_followers_only">Sequitores</string>
<string name="visibility_private">Personas specific</string>
<string name="recent_searches">Recentes</string>
<string name="skip">Saltar</string>
<string name="notification_type_follow">Nove sequaces</string>
<string name="notification_type_favorite">Favoritos</string>
<string name="notification_type_reblog">Promotiones</string>
<string name="notification_type_follow">Nove sequitores</string>
<string name="notification_type_favorite">Favorites</string>
<string name="notification_type_reblog">Impulsos</string>
<string name="notification_type_mention">Mentiones</string>
<string name="notification_type_poll">Sondages</string>
<string name="choose_account">Eliger conto</string>
<string name="err_not_logged_in">Primo accede a Mastodon</string>
<string name="err_not_logged_in">Per favor aperi session sur Mastodon primo</string>
<plurals name="cant_add_more_than_x_attachments">
<item quantity="one">Tu non pote adder plus que %d annexo de medios</item>
<item quantity="other">Tu non pote adder plus que %d annexos de medios</item>
<item quantity="one">Tu non pote adder plus de %d annexo multimedial</item>
<item quantity="other">Tu non pote adder plus de %d annexos multimedial</item>
</plurals>
<string name="media_attachment_unsupported_type">File %s es de un typo non tractate</string>
<string name="media_attachment_unsupported_type">Le file %s es de un typo non supportate</string>
<string name="media_attachment_too_big">Le file %1$s excede le dimension limite de %2$s MB</string>
<string name="settings_theme">Apparentia</string>
<string name="theme_auto">Usar apparentia de apparato</string>
<string name="theme_auto">Usar le apparentia del apparato</string>
<string name="theme_light">Clar</string>
<string name="theme_dark">Obscur</string>
<string name="settings_behavior">Comportamento</string>
<string name="settings_gif">Reproducer avatares e emoticones animate</string>
<string name="settings_custom_tabs">Aperir ligamine in</string>
<string name="settings_gif">Monstrar animation de avatares e emojis</string>
<string name="settings_custom_tabs">Aperir ligamines in</string>
<string name="settings_notifications">Notificationes</string>
<string name="settings_contribute">Contribue a Mastodon</string>
<string name="settings_tos">Terminos del servicio</string>
<string name="settings_contribute">Contribuer a Mastodon</string>
<string name="settings_tos">Conditiones de servicio</string>
<string name="settings_privacy_policy">Politica de confidentialitate</string>
<string name="settings_clear_cache">Clarar cache multimedial</string>
<string name="settings_app_version">Cache multimedial clarate</string>
<string name="media_cache_cleared">Cache multimedial clarate</string>
<string name="confirm_log_out">Disconnecter de %s?</string>
<string name="sensitive_content_explain">Le autor marcava iste medios como sensibile.</string>
<string name="avatar_description">Ir al profilo de %s</string>
<string name="settings_clear_cache">Rader cache multimedial</string>
<string name="settings_app_version">Mastodon pro Android v%1$s (%2$d)</string>
<string name="media_cache_cleared">Cache multimedial radite</string>
<string name="confirm_log_out">Clauder session sur %s?</string>
<string name="sensitive_content_explain">Le autor ha marcate iste multimedia como sensibile.</string>
<string name="avatar_description">Visitar le profilo de %s</string>
<string name="more_options">Altere optiones</string>
<string name="new_post">Nove message</string>
<string name="button_reply">Responder</string>
<string name="button_reblog">Promotion</string>
<string name="button_favorite">Favorite</string>
<string name="button_reblog">Impulso</string>
<string name="button_favorite">Adder al favorites</string>
<string name="button_share">Compartir</string>
<string name="media_no_description">Medios sin description</string>
<string name="add_media">Medios sin description</string>
<string name="media_no_description">Multimedia sin description</string>
<string name="add_media">Adder multimedia</string>
<string name="add_poll">Adder un sondage</string>
<string name="emoji">Emoticone</string>
<string name="home_timeline">Classification temporal principal</string>
<string name="emoji">Emoji</string>
<string name="home_timeline">Chronologia de initio</string>
<string name="my_profile">Mi profilo</string>
<string name="media_viewer">Visor multimedial</string>
<string name="follow_user">Sequer %s</string>
<string name="unfollowed_user">Non plus sequite %s</string>
<string name="unfollowed_user">Tu non seque plus %s</string>
<string name="followed_user">Tu ora seque %s</string>
<string name="following_user_requested">Requirite de sequer %s</string>
<string name="following_user_requested">Requestate de sequer %s</string>
<string name="open_in_browser">Aperir in navigator</string>
<string name="hide_boosts_from_user">Celar promotiones</string>
<string name="show_boosts_from_user">Monstrar promotiones</string>
<string name="signup_reason">Perque vole tu junger te?</string>
<string name="signup_reason_note">Isto nos adjutara a revider tu application.</string>
<string name="clear">Clarar</string>
<string name="hide_boosts_from_user">Celar impulsos</string>
<string name="show_boosts_from_user">Monstrar impulsos</string>
<string name="signup_reason">Perque vole tu inscriber te?</string>
<string name="signup_reason_note">Isto nos adjutara a examinar tu demanda.</string>
<string name="clear">Rader</string>
<string name="profile_header">Imagine de titulo</string>
<string name="profile_picture">Pictura de profilo</string>
<string name="profile_picture">Imagine de profilo</string>
<string name="reorder">Reordinar</string>
<string name="download">Discargar</string>
<string name="permission_required">Permisso requirite</string>
<string name="storage_permission_to_download">Le app besonia accesso a tu dispositivo de immagazinage pro salvar iste file.</string>
<string name="permission_required">Permission necessari</string>
<string name="storage_permission_to_download">Le app require accesso a tu spatio de immagazinage pro salvar iste file.</string>
<string name="open_settings">Aperir le parametros</string>
<string name="error_saving_file">Error salvante le file</string>
<string name="file_saved">File salvate</string>
<string name="downloading">Discargante…</string>
<string name="no_app_to_handle_action">Il non ha app pro gerer iste action</string>
<string name="local_timeline">Local</string>
<string name="trending_posts_info_banner">Ecce le novas re que se parlava sur Mastodon.</string>
<string name="trending_links_info_banner">Ecce le novas re que se parlava sur Mastodon.</string>
<string name="trending_posts_info_banner">Ecce le messages que gania in popularitate sur Mastodon.</string>
<string name="trending_links_info_banner">Ecce le actualitates le plus discutite sur Mastodon.</string>
<!-- %s is the server domain -->
<string name="local_timeline_info_banner">Ecce tote le messages de tote le usatores in tu servitor (%s).</string>
<string name="recommended_accounts_info_banner">Te poterea placer iste contos in base a altere que tu seque.</string>
<string name="recommended_accounts_info_banner">Iste contos poterea placer te, considerante le alteres que tu seque.</string>
<string name="see_new_posts">Nove messages</string>
<string name="load_missing_posts">Cargar messages mancante</string>
<string name="follow_back">Sequer in retorno</string>
<string name="button_follow_pending">In tractamento</string>
<string name="follows_you">Te seque</string>
<string name="manually_approves_followers">Manualmente approba le sequaces</string>
<string name="manually_approves_followers">Approbar manualmente le sequitores</string>
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
<plurals name="x_followers">
<item quantity="one">%,d sequace</item>
<item quantity="other">%,d sequace</item>
<item quantity="one">%,d sequitor</item>
<item quantity="other">%,d sequitores</item>
</plurals>
<plurals name="x_following">
<item quantity="one">%,d sequite</item>
@@ -259,12 +259,12 @@
<item quantity="other">%,d favorites</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d promovite</item>
<item quantity="one">%,d impulso</item>
<item quantity="other">%,d promovites</item>
</plurals>
<string name="time_now">ora</string>
<string name="edit_history">Chronologia de redaction</string>
<string name="last_edit_at_x">Ultime redaction %s</string>
<string name="edit_history">Historia de modificationes</string>
<string name="last_edit_at_x">Ultime modification %s</string>
<string name="time_just_now">justo ora</string>
<plurals name="x_seconds_ago">
<item quantity="one">%d secunda retro</item>
@@ -274,26 +274,26 @@
<item quantity="one">%d minuta retro</item>
<item quantity="other">%d minutas retro</item>
</plurals>
<string name="edited_timestamp">redigite %s</string>
<string name="edited_timestamp">modificate %s</string>
<string name="edit_original_post">Message original</string>
<string name="edit_text_edited">Testo redigite</string>
<string name="edit_spoiler_added">Aviso re contento addite</string>
<string name="edit_spoiler_edited">Aviso re contento redigite</string>
<string name="edit_spoiler_removed">Aviso re contento removite</string>
<string name="edit_text_edited">Texto modificate</string>
<string name="edit_spoiler_added">Advertimento de contento addite</string>
<string name="edit_spoiler_edited">Advertimento de contento modificate</string>
<string name="edit_spoiler_removed">Advertimento de contento removite</string>
<string name="edit_poll_added">Sondage addite</string>
<string name="edit_poll_edited">Sondage redigite</string>
<string name="edit_poll_edited">Sondage modificate</string>
<string name="edit_poll_removed">Sondage removite</string>
<string name="edit_media_added">Medios addite</string>
<string name="edit_media_removed">Medios removite</string>
<string name="edit_media_reordered">Medios reordinate</string>
<string name="edit_marked_sensitive">Aviso re contento redigite</string>
<string name="edit_media_added">Multimedia addite</string>
<string name="edit_media_removed">Multimedia removite</string>
<string name="edit_media_reordered">Multimedia reordinate</string>
<string name="edit_marked_sensitive">Marcate como sensibile</string>
<string name="edit_marked_not_sensitive">Marcate como non sensibile</string>
<string name="edit_multiple_changed">Message redigite</string>
<string name="edit">Rediger</string>
<string name="discard_changes">Refusar le modificationes?</string>
<string name="upload_failed">Cargamento fallite</string>
<string name="edit_multiple_changed">Message modificate</string>
<string name="edit">Modificar</string>
<string name="discard_changes">Abandonar le modificationes?</string>
<string name="upload_failed">Incargamento fallite</string>
<string name="file_size_bytes">%d bytes</string>
<string name="file_size_kb">%.2f KB</string>
<string name="file_size_kb">%.2f kB</string>
<string name="file_size_mb">%.2f MB</string>
<string name="file_size_gb">%.2f GB</string>
<string name="upload_processing">Processante…</string>
@@ -301,131 +301,133 @@
<string name="download_update">Discargar (%s)</string>
<string name="install_update">Installar</string>
<string name="privacy_policy_title">Tu confidentialitate</string>
<string name="privacy_policy_subtitle">Ben que le app Mastodon non collige alcun datos, le servitor per que tu te inscribe pote haber un differente regulamento.\n\nSi tu dissenti del regulamento pro %s, tu pote retornar e seliger un servitor differente.</string>
<string name="i_agree">Io consenti</string>
<string name="privacy_policy_subtitle">Ben que le app Mastodon non collige alcun datos, le servitor al qual tu te inscribe pote haber un altere politica.\n\nSi tu non accepta le politica de %s, tu pote retornar e seliger un altere servitor.</string>
<string name="i_agree">Io accepta</string>
<string name="empty_list">Iste lista es vacue</string>
<string name="instance_signup_closed">Iste servitor non accepta nove registrationes.</string>
<string name="instance_signup_closed">Iste servitor non accepta nove inscriptiones.</string>
<string name="text_copied">Copiate al area de transferentia</string>
<string name="add_bookmark">Adder al marcapaginas</string>
<string name="remove_bookmark">Remover marcapagina</string>
<string name="bookmarks">Marcapaginas</string>
<string name="your_favorites">Tu favorite</string>
<string name="login_title">Ben tornate</string>
<string name="your_favorites">Tu favorites</string>
<string name="login_title">Benvenite de novo</string>
<string name="login_subtitle">Aperi session con le servitor ubi tu ha create tu conto.</string>
<string name="server_url">URL del servitor</string>
<string name="server_filter_any_language">Qualcunque lingua</string>
<string name="server_filter_instant_signup">Inscription instantanee</string>
<string name="server_filter_manual_review">Revision manual</string>
<string name="server_filter_any_signup_speed">Qualcunque velocitate de inscription</string>
<string name="server_filter_region_europe">Europa</string>
<string name="server_filter_region_north_america">Nord America</string>
<string name="server_filter_region_south_america">Sud America</string>
<string name="server_filter_region_north_america">America del Nord</string>
<string name="server_filter_region_south_america">America del Sud</string>
<string name="server_filter_region_africa">Africa</string>
<string name="server_filter_region_asia">Asia</string>
<string name="server_filter_region_oceania">Oceania</string>
<string name="not_accepting_new_members">Non acceptante nove membros</string>
<string name="not_accepting_new_members">Non accepta nove membros</string>
<string name="category_special_interests">Interesses special</string>
<string name="signup_passwords_dont_match">Contrasignos discorde</string>
<string name="profile_add_row">Adder rango</string>
<string name="signup_passwords_dont_match">Le contrasignos non correponde</string>
<string name="profile_add_row">Adder linea</string>
<string name="profile_setup">Configuration del profilo</string>
<string name="profile_setup_subtitle">Tu pote sempre completar isto plus tarde in le Scheda de profilo.</string>
<string name="follow_all">Sequer toto</string>
<string name="server_rules_disagree">Io dissenti</string>
<string name="privacy_policy_explanation">TL;DR: Nos non collige o processa alco.</string>
<string name="profile_setup_subtitle">Tu pote sempre completar isto plus tarde in le scheda Profilo.</string>
<string name="follow_all">Sequer totes</string>
<string name="server_rules_disagree">Non acceptar</string>
<string name="privacy_policy_explanation">Summario: Nos non collige o processa alcun cosa.</string>
<!-- %s is server domain -->
<string name="server_policy_disagree">Io dissenti de %s</string>
<string name="server_policy_disagree">Io non es de accordo con %s</string>
<string name="profile_bio">Bio</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<string name="sending_follows">Sequente usatores…</string>
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
<string name="signup_email_domain_blocked">%1$s non permitte registrationes de %2$s. Tenta un altere o&lt;a&gt;selige un servitor differente&lt;/a&gt;.</string>
<string name="spoiler_show">Monstrar comocunque</string>
<string name="signup_email_domain_blocked">%1$s non permitte le inscriptiones de %2$s. Tenta un altere dominio o &lt;a&gt;elige un altere servitor&lt;/a&gt;.</string>
<string name="spoiler_show">Monstrar in omne caso</string>
<string name="spoiler_hide">Re-celar</string>
<string name="poll_multiple_choice">Selige un o plus</string>
<string name="save_changes">Salvar le cambiamentos</string>
<string name="profile_featured">Favorite</string>
<string name="profile_timeline">Classification temporal</string>
<string name="profile_timeline">Chronologia</string>
<string name="view_all">Vider toto</string>
<string name="profile_endorsed_accounts">Contos</string>
<string name="verified_link">Ligamine verificate</string>
<string name="show">Monstrar</string>
<string name="hide">Celar</string>
<string name="join_default_server">Junge te a %s</string>
<string name="pick_server">Elige un altere servitor</string>
<string name="join_default_server">Inscribe te a %s</string>
<string name="pick_server">Eliger un altere servitor</string>
<string name="signup_or_login">o</string>
<string name="learn_more">Pro saper plus</string>
<string name="welcome_to_mastodon">Benvenite in Mastodon</string>
<string name="welcome_paragraph1">Mastodon es un rete social decentralisate, significa que nulle singule compania controla illo. Illo es formate de multe servitores que functiona in maniera independente, totos connectite insimul.</string>
<string name="what_are_servers">Qual es servitores?</string>
<string name="welcome_paragraph2">Cata conto Mastodon es hospite sur un servitor, cata con su proprie valores, regulas, e administratores. Non importa qual tu selige, tu pote sequer e interager con le personas sur ulle servitor.</string>
<string name="opening_link">Aperiente ligamine…</string>
<string name="welcome_to_mastodon">Benvenite a Mastodon</string>
<string name="welcome_paragraph1">Mastodon es un rete social decentralisate, lo que vole dicer que necun interprisa singule lo controla. Illo se compone de multe servitores independente, totes connectite inter se.</string>
<string name="what_are_servers">Que es le servitores?</string>
<string name="welcome_paragraph2">Cata conto Mastodon es hospitate sur un servitor, cata un con su proprie valores, regulas, e administratores. Non importa qual servitor tu selige, tu pote sequer e interager con le personas sur tote le servitores.</string>
<string name="opening_link">Apertura del ligamine…</string>
<string name="link_not_supported">Iste ligamine non es supportate in le app</string>
<string name="log_out_all_accounts">Disconnecter de tote le contos</string>
<string name="confirm_log_out_all_accounts">Disconnecter de tote le contos?</string>
<string name="retry">Retentar</string>
<string name="post_failed">Falta a inviar message</string>
<string name="log_out_all_accounts">Clauder session de tote le contos</string>
<string name="confirm_log_out_all_accounts">Clauder session de tote le contos?</string>
<string name="retry">Tentar de novo</string>
<string name="post_failed">Invio de message fallite</string>
<!-- %s is formatted file size ("467 KB image") -->
<string name="attachment_description_image">%s immagine</string>
<string name="attachment_description_video">%s video</string>
<string name="attachment_description_audio">%s audio</string>
<string name="attachment_description_unknown">%s file</string>
<string name="attachment_description_image">Imagine de %s</string>
<string name="attachment_description_video">Video de %s</string>
<string name="attachment_description_audio">Audio de %s</string>
<string name="attachment_description_unknown">File de %s</string>
<string name="attachment_type_image">Imagine</string>
<string name="attachment_type_video">Video</string>
<string name="attachment_type_audio">Audio</string>
<string name="attachment_type_gif">GIF</string>
<string name="attachment_type_unknown">File</string>
<string name="attachment_x_percent_uploaded">%d%% cargate</string>
<string name="attachment_x_percent_uploaded">%d%% incargate</string>
<string name="add_poll_option">Adder option de sondage</string>
<string name="poll_length">Longor de sondage</string>
<string name="poll_length">Durata del sondage</string>
<string name="poll_style">Stilo</string>
<string name="compose_poll_single_choice">Seliger un</string>
<string name="compose_poll_single_choice">Selige un</string>
<string name="compose_poll_multiple_choice">Selection multiple</string>
<string name="delete_poll_option">Deler option de sondage</string>
<string name="poll_style_title">Stilo de sondage</string>
<string name="alt_text">Texto alt</string>
<string name="poll_style_title">Stilo del sondage</string>
<string name="alt_text">Texto alternative</string>
<string name="help">Adjuta</string>
<string name="what_is_alt_text">Que es le texto alt?</string>
<string name="alt_text_help">Le texto alt offere descriptiones de imagine pro personas con insufficientias visive, connexiones con basse largessa de banda, o qui cerca contexto extra.\n\nTu pote meliorar le accessibilitate e le comprension pro totes scribente texto alt clar, concise, e objective.\n\n<ul><li>Capturar elementos importante</li>\n<li>Summarisar texto in imagines</li>\n<li>Usar structura de phrase regular</li>\n<li>Evitar informationes redundante</li>\n<li>Examinar tendentias e discopertas clave in figuras complexe (como diagrammas o mappas)</li></ul></string>
<string name="edit_post">Rediger message</string>
<string name="no_verified_link">Ligamine non verificate</string>
<string name="compose_autocomplete_emoji_empty">Navigar per emoticones</string>
<string name="what_is_alt_text">Que es le texto alternative?</string>
<string name="alt_text_help">Le texto alternative forni descriptiones de imagines a personas con impedimentos visual, con connexiones lente, o qui cerca contexto additional.\n\nTu pote meliorar le accessibilitate e le comprension pro totes scribente un texto alternative clar, concise e objective.\n\n<ul><li>Captura le elementos importante</li>\n<li>Summarisa texto in imagines</li>\n<li>Usa le structura de phrase normal</li>\n<li>Evita information redundante</li>\n<li>In figuras complexe (como diagrammas o mappas), concentra te sur le tendentias e punctos clave</li></ul></string>
<string name="edit_post">Modificar message</string>
<string name="no_verified_link">Necun ligamine verificate</string>
<string name="compose_autocomplete_emoji_empty">Percurrer emojis</string>
<string name="compose_autocomplete_users_empty">Trova qui tu cerca</string>
<string name="no_search_results">Nihil trovate pro iste terminos de recerca</string>
<string name="language">Lingua</string>
<string name="language_default">Predefinite</string>
<string name="language_system">Systema</string>
<string name="language_detecting">Detectante lingua</string>
<string name="language_cant_detect">Impossibile detectar le lingua</string>
<string name="language_detected">Relevate</string>
<string name="media_hidden">Medios celate</string>
<string name="language_detecting">Detection de lingua</string>
<string name="language_cant_detect">Impossibile deteger le lingua</string>
<string name="language_detected">Detegite</string>
<string name="media_hidden">Multimedia celate</string>
<string name="post_hidden">Message celate</string>
<string name="report_title_post">Reportar message</string>
<string name="forward_report_explanation">Le conto es del un altere servitor. Inviar anque illac un copia anonyme de iste reporto?</string>
<string name="forward_report_explanation">Le conto es de un altere servitor. Inviar un copia anonymisate de iste reporto a ille servitor tamben?</string>
<!-- %s is the server domain -->
<string name="forward_report_to_server">Inultrar a %s</string>
<string name="forward_report_to_server">Reinviar a %s</string>
<!-- Shown on the "stamp" on the screen that appears after you report a post/user. Please keep the translation short, preferably a single word -->
<string name="reported">Reportate</string>
<string name="report_unfollow_explanation">Non plus vider lor messages in tu fluxo principal, cessar de sequer los.</string>
<string name="muted_user">Silentiate %s</string>
<string name="report_sent_already_blocked">Tu ha jam blocate iste usator, assi il ha nihil altere que tu debe facer dum nos revide tu reporto.</string>
<string name="report_personal_already_blocked">Tu ha jam blocate iste usator, assi il ha nihil altere que tu debe facer.\n\nGratias pro adjutar a mantener Mastodon un posto secur pro totes!</string>
<string name="blocked_user">Blocate %s</string>
<string name="report_unfollow_explanation">Pro non plus vider su messages in tu fluxo principal, cessa de sequer le.</string>
<string name="muted_user">%s silentiate</string>
<string name="report_sent_already_blocked">Tu ha ja blocate iste usator, dunque il ha nihil altere que tu debe facer durante que nos examina tu reporto.</string>
<string name="report_personal_already_blocked">Tu ha ja blocate iste usator, dunque il ha nihil altere que tu debe facer.\n\nGratias pro adjutar a mantener Mastodon secur pro totes!</string>
<string name="blocked_user">%s blocate</string>
<string name="mark_all_notifications_read">Marcar toto como legite</string>
<string name="settings_display">Schermo</string>
<string name="settings_filters">Filtros</string>
<string name="settings_server_explanation">Summario, regulas, moderatores</string>
<string name="settings_server_explanation">Vista general, regulas, moderatores</string>
<!-- %s is the app name (Mastodon, key app_name). I made it a placeholder so everything Just Works™ with forks -->
<string name="about_app">A proposito de %s</string>
<string name="default_post_language">Lingua predefinite del message</string>
<string name="settings_alt_text_reminders">Adder mementos de texto alt</string>
<string name="settings_confirm_unfollow">Demandar ante cessar de sequer alcuno</string>
<string name="settings_confirm_boost">Demandar ante promover</string>
<string name="settings_confirm_delete_post">Demandar ante deler messages</string>
<string name="default_post_language">Lingua predefinite de messages</string>
<string name="settings_alt_text_reminders">Adder rememorationes de texto alternative</string>
<string name="settings_confirm_unfollow">Demandar ante de cessar de sequer alcuno</string>
<string name="settings_confirm_boost">Demandar ante de impulsar</string>
<string name="settings_confirm_delete_post">Demandar ante de deler messages</string>
<string name="pause_all_notifications">Pausar toto</string>
<string name="pause_notifications_off">Inactive</string>
<string name="notifications_policy_anyone">Quicunque</string>
<string name="notifications_policy_followed">Illes qui te seque</string>
<string name="notifications_policy_follower">Illes que tu seque</string>
<string name="notifications_policy_followed">Personas qui te seque</string>
<string name="notifications_policy_follower">Personas que tu seque</string>
<string name="notifications_policy_no_one">Nemo</string>
<string name="settings_notifications_policy">Reciper notificationes ab</string>
<string name="settings_notifications_policy">Reciper notificationes de</string>
<string name="notification_type_mentions_and_replies">Mentiones e responsas</string>
<string name="pause_all_notifications_title">Pausar tote le notificationes</string>
<plurals name="x_weeks">
@@ -438,21 +440,21 @@
<string name="yesterday">heri</string>
<string name="tomorrow">deman</string>
<!-- %s is the timestamp ("tomorrow at 12:34") -->
<string name="pause_notifications_ends">Fini %s</string>
<string name="pause_notifications_ends">Termina %s</string>
<!-- %s is the timestamp ("tomorrow at 12:34") -->
<string name="pause_notifications_banner">Le notificationes recomenciara %s.</string>
<string name="resume_notifications_now">Resumer ora</string>
<string name="open_system_notification_settings">Ir a parametros de notificationes</string>
<string name="pause_notifications_banner">Le notificationes reprendera %s.</string>
<string name="resume_notifications_now">Reprender ora</string>
<string name="open_system_notification_settings">Visitar le parametros de notification</string>
<string name="about_server">A proposito</string>
<string name="server_rules">Regulas</string>
<string name="server_administrator">Administrator</string>
<string name="send_email_to_server_admin">Administrator de messages</string>
<string name="notifications_disabled_in_system">Activa notificationes ab parametros de tu apparato pro vider actualisationes de ubique.</string>
<string name="send_email_to_server_admin">Contactar administrator</string>
<string name="notifications_disabled_in_system">Activa le notificationes desde le parametros de tu apparato pro vider actualisationes de ubique.</string>
<string name="settings_even_more">Ancora plus parametros</string>
<string name="settings_show_cws">Monstrar avisos re contento</string>
<string name="settings_hide_sensitive_media">Coperir le medios marcate como sensibile</string>
<string name="settings_show_interaction_counts">Computo de interaction de messages</string>
<string name="settings_show_emoji_in_names">Emoticone personalisate in nomines monstrate</string>
<string name="settings_show_cws">Monstrar advertimentos de contento</string>
<string name="settings_hide_sensitive_media">Coperir le files multimedial marcate como sensibile</string>
<string name="settings_show_interaction_counts">Numero de interactiones con le message</string>
<string name="settings_show_emoji_in_names">Emoji personalisate in nomines monstrate</string>
<plurals name="in_x_seconds">
<item quantity="one">in %d secunda</item>
<item quantity="other">in %d secundas</item>
@@ -469,14 +471,14 @@
<item quantity="one">%d hora retro</item>
<item quantity="other">%d horas retro</item>
</plurals>
<string name="alt_text_reminder_title">Medios mancante de texto alt</string>
<string name="alt_text_reminder_title">Files multimedial sin texto alternative</string>
<plurals name="alt_text_reminder_x_images">
<item quantity="one">%s de tu imagines care de texto alt. Inviar comocunque?</item>
<item quantity="other">%s de tu imagines care de texto alt. Inviar comocunque?</item>
<item quantity="one">%s de tu imagines non ha texto alternative. Inviar nonobstante?</item>
<item quantity="other">%s de tu imagines non ha texto alternative. Inviar nonobstante?</item>
</plurals>
<plurals name="alt_text_reminder_x_attachments">
<item quantity="one">%s de tu annexos de medios care de texto alt. Inviar comocunque?</item>
<item quantity="other">%s de tu annexos de medios care de texto alt. Inviar comocunque?</item>
<item quantity="one">%s de tu annexos multimedial non ha texto alternative. Inviar nonobstante?</item>
<item quantity="other">%s de tu annexos multimedial non ha texto alternative. Inviar nonobstante?</item>
</plurals>
<string name="count_one">Un</string>
<string name="count_two">Duo</string>
@@ -484,7 +486,7 @@
<string name="count_four">Quatro</string>
<string name="alt_text_reminder_post_anyway">Publicar</string>
<!-- %s is the username -->
<string name="unfollow_confirmation">Non plus sequer %s?</string>
<string name="unfollow_confirmation">Cessar de sequer %s?</string>
<string name="filter_active">Active</string>
<string name="filter_inactive">Inactive</string>
<string name="settings_add_filter">Adder filtro</string>
@@ -492,32 +494,32 @@
<string name="settings_filter_duration">Duration</string>
<string name="settings_filter_muted_words">Parolas silentiate</string>
<string name="settings_filter_context">Silentiar de</string>
<string name="settings_filter_show_cw">Monstrar con avisos re contento</string>
<string name="settings_filter_show_cw_explanation">Ancora monstra messages que concorda iste filtro, ma detra un aviso re contento</string>
<string name="settings_filter_show_cw">Monstrar con advertimento de contento</string>
<string name="settings_filter_show_cw_explanation">Monstrar le messages que corresponde a iste filtro mesmo si illos ha un advertimento de contento</string>
<string name="settings_delete_filter">Deler filtro</string>
<string name="filter_duration_forever">Sempre</string>
<string name="filter_duration_forever">Pro sempre</string>
<!-- %s is the timestamp ("tomorrow at 12:34") -->
<string name="settings_filter_ends">Fini %s</string>
<string name="settings_filter_ends">Termina %s</string>
<plurals name="settings_x_muted_words">
<item quantity="one">%d parola o expression silentiate</item>
<item quantity="other">%d parolas o expressiones silentiate</item>
<item quantity="one">%d parola o phrase silentiate</item>
<item quantity="other">%d parolas o phrases silentiate</item>
</plurals>
<string name="selection_2_options">%1$s e %2$s</string>
<string name="selection_3_options">%1$s, %2$s, e %3$s</string>
<string name="selection_4_or_more">%1$s, %2$s, e %3$d altero</string>
<string name="filter_context_home_lists">Pagina de initio e listas</string>
<string name="selection_3_options">%1$s, %2$s e %3$s</string>
<string name="selection_4_or_more">%1$s, %2$s, e %3$d alteres</string>
<string name="filter_context_home_lists">Initio e listas</string>
<string name="filter_context_notifications">Notificationes</string>
<string name="filter_context_public_timelines">Chronologias public</string>
<string name="filter_context_threads_replies">Argumentos e responsas</string>
<string name="filter_context_threads_replies">Discussiones e responsas</string>
<string name="filter_context_profiles">Profilos</string>
<string name="settings_filter_title">Titulo</string>
<string name="settings_delete_filter_title">Deler filtro “%s”?</string>
<string name="settings_delete_filter_confirmation">Iste filtro sera delite de tu conto sur tote tu apparatos.</string>
<string name="settings_delete_filter_confirmation">Iste filtro essera delite de tu conto sur tote tu apparatos.</string>
<string name="add_muted_word">Adder parola silentiate</string>
<string name="edit_muted_word">Rediger parola silentiate</string>
<string name="edit_muted_word">Modificar parola silentiate</string>
<string name="add">Adder</string>
<string name="filter_word_or_phrase">Messages con “%s”</string>
<string name="filter_add_word_help">Le parolas es insensibile a majuscule/minuscule e solo concorda con parolas integre.\n\nSi tu filtra per parola clave “Apple,” illo celara messages que contine “apple” o “aPpLe” ma non “pineapple.”</string>
<string name="filter_word_or_phrase">Parola o phrase</string>
<string name="filter_add_word_help">Le parolas non distingue inter majusculas e minusculas e corresponde solmente a parolas complete.\n\nSi tu filtra per le parola clave “Lingua,” le messages que contine “lingua” o “lInGuA” essera celate, ma non “interlingua.”</string>
<string name="settings_delete_filter_word">Deler parola “%s”?</string>
<string name="enter_selection_mode">Seliger</string>
<string name="select_all">Seliger toto</string>
@@ -532,14 +534,14 @@
<item quantity="other">%d seligite</item>
</plurals>
<string name="required_form_field_blank">Non pote esser vacue</string>
<string name="filter_word_already_in_list">Jam in le lista</string>
<string name="app_update_ready">App preste actualisate</string>
<string name="filter_word_already_in_list">Ja presente in le lista</string>
<string name="app_update_ready">Actualisation del app preste</string>
<string name="app_update_version">Version %s</string>
<string name="downloading_update">Discargante (%d%%)</string>
<!-- Shown like a content warning, %s is the name of the filter -->
<string name="post_matches_filter_x">Concorda con filtro “%s”</string>
<string name="search_mastodon">Cercar Mastodon</string>
<string name="clear_all">Clarar toto</string>
<string name="post_matches_filter_x">Corresponde al filtro “%s”</string>
<string name="search_mastodon">Cercar in Mastodon</string>
<string name="clear_all">Rader toto</string>
<string name="search_open_url">Aperir URL in Mastodon</string>
<string name="posts_matching_hashtag">Messages con “%s”</string>
<string name="search_go_to_account">Ir a %s</string>
@@ -555,8 +557,8 @@
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Traducite ab %1$s usante %2$s</string>
<string name="translation_show_original">Monstrar original</string>
<string name="translation_failed">Traduction fallite. Forsan le administrator non ha activate traductiones sur iste servitor o sur iste servitor es exequite un version de Mastodon plus vetere ubi le traductiones non es ancora supportate.</string>
<string name="settings_privacy">Confidentialitate e capacitate</string>
<string name="translation_failed">Traduction fallite. Forsan le administrator non ha activate le traductiones sur iste servitor, o iste servitor usa un version de Mastodon plus ancian in le qual le traductiones non es ancora supportate.</string>
<string name="settings_privacy">Confidentialitate e portata</string>
<string name="settings_discoverable">Evidentiar le profilo e messages in le algorithmos de discoperta</string>
<string name="settings_indexable">Includer messages public in le resultatos de recerca</string>
<plurals name="x_participants">
@@ -567,21 +569,21 @@
<item quantity="one">%,d message hodie</item>
<item quantity="other">%,d messages hodie</item>
</plurals>
<string name="error_playing_video">Error reproducente video</string>
<string name="error_playing_video">Error de reproduction del video</string>
<string name="timeline_following">Initio</string>
<string name="lists">Listas</string>
<string name="followed_hashtags">Hashtags sequite</string>
<string name="manage_lists">Gerer le listas</string>
<string name="manage_hashtags">Gerer hashtags</string>
<!-- Screen reader description for the menu on the home timeline screen -->
<string name="dropdown_menu">Menu a cadita</string>
<string name="dropdown_menu">Menu disrolante</string>
<string name="edit_list">Modificar lista</string>
<string name="list_members">Listar membros</string>
<string name="delete_list">Deler lista</string>
<!-- %s is the name of the list -->
<string name="delete_list_confirm">Deler “%s”?</string>
<string name="list_exclusive">Celar membros in Lista de sequites</string>
<string name="list_exclusive_subtitle">Si alcuno es sur iste lista, celar illes in tu classification temporal de sequites pro evitar de vider lor messages duo vices.</string>
<string name="list_exclusive">Celar membros in Sequites</string>
<string name="list_exclusive_subtitle">Si alcuno es sur iste lista, celar iste persona in tu chronologia de personas sequite pro evitar de vider su messages duo vices.</string>
<string name="list_name">Nomine del lista</string>
<string name="list_show_replies_to">Monstrar responsas a</string>
<string name="list_replies_no_one">Nemo</string>
@@ -597,11 +599,11 @@
<string name="manage_user_lists">Gerer le lista sur que appare %s</string>
<string name="remove_from_list">Remover del lista</string>
<string name="confirm_remove_list_member">Remover membro?</string>
<string name="no_followed_hashtags_title">Tene te al currente con interesses sequente hashtags</string>
<string name="no_followed_hashtags_subtitle">Los sequite apparera ci</string>
<string name="no_lists_title">Organisa tu fluxo principal con Listas</string>
<string name="no_lists_subtitle">Le tue apparera ci</string>
<string name="manage_accounts">Adder o mutar contos</string>
<string name="no_followed_hashtags_title">Seque hashtags pro tener te al currente con tu interesses</string>
<string name="no_followed_hashtags_subtitle">Illos que tu seque apparera hic</string>
<string name="no_lists_title">Organisa tu fluxo de initio con Listas</string>
<string name="no_lists_subtitle">Le tue apparera hic</string>
<string name="manage_accounts">Adder o cambiar de conto</string>
<plurals name="x_posts_recently">
<item quantity="one">%,d message recente</item>
<item quantity="other">%,d messages recente</item>
@@ -613,42 +615,42 @@
<string name="list_no_members">Nulle membros ancora</string>
<string name="list_find_users">Trovar usatores a adder</string>
<string name="reply_to_user">Responder a: %s</string>
<string name="posted_at">Inviate %s</string>
<string name="non_mutual_sheet_title">Hallo, nove connexion!</string>
<string name="non_mutual_sheet_text">Pare que tu va responder a alcuno qui non es ancora in connexion reciproc. Que nos face un grande prime impression.</string>
<string name="got_it">Io comprendeva</string>
<string name="dont_remind_again">Non rememorar me ancora</string>
<string name="posted_at">Inviate a %s</string>
<string name="non_mutual_sheet_title">Salute, nove connexion!</string>
<string name="non_mutual_sheet_text">Pare que tu es sur le puncto de responder a un persona qui non es ancora un connexion reciproc. Que nos face un bon prime impression.</string>
<string name="got_it">Comprendite</string>
<string name="dont_remind_again">Non rememorar me de novo</string>
<!-- %s is a time interval ("5 months") -->
<string name="old_post_sheet_title">Iste message es %s vetere</string>
<string name="old_post_sheet_text">Tu pote ancora responder, ma illo pote non plus esser pertinente.</string>
<string name="old_post_sheet_title">Iste message ha %s</string>
<string name="old_post_sheet_text">Tu pote ancora responder, ma poterea non plus esser pertinente.</string>
<plurals name="x_months">
<item quantity="one">%,d mense</item>
<item quantity="other">%,d menses</item>
</plurals>
<string name="more_than_two_years">plus que 2 annos</string>
<string name="more_than_two_years">plus de 2 annos</string>
<string name="non_mutual_title1">Remane respectuose e pertinente</string>
<string name="non_mutual_text1">Cura que tu responsa es cortese e in thema.</string>
<string name="non_mutual_title2">Imbracia le gentilessa</string>
<string name="non_mutual_text1">Assecura te que tu responsa es cortese e sur le topico.</string>
<string name="non_mutual_title2">Imbracia le benevolentia</string>
<string name="non_mutual_text2">Un tono positive sempre es appreciate.</string>
<string name="non_mutual_title3">Sia aperte</string>
<string name="non_mutual_text3">Le stilo de conversation de cata un es unic. Sia preste a adaptar te.</string>
<string name="make_profile_discoverable">Render mi profilo detectabile</string>
<string name="discoverability">Detectabilitate</string>
<string name="discoverability_help">Quando tu opta pro le detectabilitate sur Mastodon, tu messages pote apparer in resultatos del recerca e tendentia.\n\nTu profilo pote esser suggerite a personas con interesses simile al tue.\n\nrefusar non cela tu profilo si alcuno te recerca per nomine.</string>
<string name="non_mutual_text3">Le stilo de conversation de cata uno es unic. Sia preste a adaptar te.</string>
<string name="make_profile_discoverable">Render mi profilo discoperibile</string>
<string name="discoverability">Discoperibilitate</string>
<string name="discoverability_help">Quando tu opta pro esser discoperibile sur Mastodon, tu messages pote apparer in resultatos de recerca e in le tendentias.\n\nTu profilo pote esser suggerite a personas con interesses simile al tues.\n\nOptar contra isto non cela tu profilo si alcuno te cerca per nomine.</string>
<string name="app_version_copied">Numero de version copiate al area de transferentia</string>
<string name="onboarding_recommendations_intro">Tu cura tu proprie fluxo principal.
Quanto plus personas tu seque, tanto plus active e interessante illo sera.</string>
<string name="onboarding_recommendations_title">Personalisa tu fluxo principal</string>
<string name="onboarding_recommendations_intro">Tu gere tu proprie fluxo de initio.
Quanto plus personas tu seque, tanto plus active e interessante illo essera.</string>
<string name="onboarding_recommendations_title">Personalisar tu fluxo de initio</string>
<string name="article_by_author">Per %s</string>
<string name="info">Info</string>
<string name="button_reblogged">Promovite</string>
<string name="button_reblogged">Impulsate</string>
<string name="button_favorited">Favorite</string>
<string name="bookmarked">Marcapaginas addite</string>
<string name="join_server_x_with_invite">Junger se a %s con invitation</string>
<string name="bookmarked">In marcapaginas</string>
<string name="join_server_x_with_invite">Inscriber se a %s con invitation</string>
<string name="expired_invite_link">Ligamine de invitation expirate</string>
<string name="expired_clipboard_invite_link_alert">Le ligamine de invitation pro %1$s in tu area de transferentia ha expirate e non pote esser usate pro inscriber te.\n\nTu pote peter un nove ligamine ab un usator existente, inscriber te per %2$s, o seliger un altere servitor per que inscriber te.</string>
<string name="expired_clipboard_invite_link_alert">Le ligamine de invitation pro %1$s in tu area de transferentia ha expirate e non pote esser usate pro inscriber te.\n\nTu pote peter un nove ligamine a un usator existente, inscriber te a %2$s, o seliger un altere servitor al qual inscriber te.</string>
<string name="invalid_invite_link">Ligamine de invitation non valide</string>
<string name="invalid_clipboard_invite_link_alert">Le ligamine de invitation pro %1$s in tu area de transferentia non es valide e non pote esser usate pro inscriber te.\n\nTu pote peter un nove ligamine ab un usator existente, inscriber te per %2$s, o seliger un altere servitor per que inscriber te.</string>
<string name="invalid_clipboard_invite_link_alert">Le ligamine de invitation pro %1$s in tu area de transferentia non es valide e non pote esser usate pro inscriber te.\n\nTu pote peter un nove ligamine a un usator existente, inscriber te a %2$s, o seliger un altere servitor al qual inscriber te.</string>
<string name="use_invite_link">Usar ligamine de invitation</string>
<string name="enter_invite_link">Insere le ligamine de invitation</string>
<string name="this_invite_is_invalid">Iste ligamine de invitation non es valide.</string>
@@ -660,22 +662,22 @@ Quanto plus personas tu seque, tanto plus active e interessante illo sera.</stri
<string name="user_can_still_see_your_posts">Illes pote ancora vider tu messages, ma tu non videra le lore.</string>
<string name="you_wont_see_user_mentions">Tu non videra messages que les mentiona.</string>
<string name="user_can_mention_and_follow_you">Illes pote mentionar e sequer te, ma tu non les videra.</string>
<string name="unmuted_user_x">Non plus silentiate %s</string>
<string name="unmuted_user_x">%s non es plus silentiate</string>
<string name="block_user_confirm_title">Blocar usator?</string>
<string name="user_can_see_blocked">Illes pote vider que illes es blocate.</string>
<string name="user_cant_see_each_other_posts">Illes non pote vider tu messages e tu non videra le lore.</string>
<string name="user_cant_mention_or_follow_you">Illes non pote mentionar o sequer te.</string>
<string name="unblocked_user_x">Disblocate %s</string>
<string name="user_can_see_blocked">Le persona pote saper de esser blocate.</string>
<string name="user_cant_see_each_other_posts">Iste persona non potera vider tu messages e tu non videra le sues.</string>
<string name="user_cant_mention_or_follow_you">Le persona non pote mentionar te o sequer te.</string>
<string name="unblocked_user_x">%s disblocate</string>
<string name="block_domain_confirm_title">Blocar dominio?</string>
<string name="do_block_server">Blocar servitor</string>
<string name="block_user_x_instead">Blocar %s in vice</string>
<string name="block_user_x_instead">Blocar %s in su loco</string>
<string name="users_cant_see_blocked">Tu non videra messages o notificationes de usatores sur iste servitor.</string>
<string name="you_wont_see_server_posts">Tu non videra ulle messages de usatores sur iste servitor.</string>
<string name="server_followers_will_be_removed">Tu sequaces ab iste servitor sera removite.</string>
<string name="server_cant_mention_or_follow_you">Nemo ab iste servitor pote sequer te.</string>
<string name="you_wont_see_server_posts">Tu non videra messages de usatores sur iste servitor.</string>
<string name="server_followers_will_be_removed">Tu sequitores de iste servitor essera removite.</string>
<string name="server_cant_mention_or_follow_you">Necuno de iste servitor pote sequer te.</string>
<string name="server_can_interact_with_older">Le personas de iste servitor pote interager con tu messages ancian.</string>
<string name="unblocked_domain_x">Dominio %s disblocate</string>
<string name="handle_help_title">Que ha il in un manico?</string>
<string name="handle_help_title">Que significa un pseudonymo?</string>
<string name="handle_title">Su pseudonymo</string>
<string name="handle_username_explanation">Su identificator unic sur su servitor. Es possibile trovar usatores con le mesme nomine de usator sur servitores differente.</string>
<string name="handle_title_own">Tu pseudonymo</string>
@@ -685,11 +687,11 @@ Quanto plus personas tu seque, tanto plus active e interessante illo sera.</stri
<string name="handle_explanation">Un pseudonymo indica qui un persona es e ubi se trova, de maniera que tu pote interager con personas sur tote le rete social de &lt;a&gt;platteformas basate sur ActivityPub&lt;/a&gt;.</string>
<string name="handle_server_explanation_own">Tu casa digital, ubi vive tote tu messages. Non te place? Cambia de servitor a omne momento e porta tu sequitores con te.</string>
<string name="handle_explanation_own">Perque tu pseudonymo indica qui tu es e ubi tu te trova, le gente pote interager con te desde tote le rete social de &lt;a&gt;platteformas basate sur ActivityPub&lt;/a&gt;.</string>
<string name="what_is_activitypub_title">Ques ActivityPub?</string>
<string name="what_is_activitypub">ActivityPub es como le lingua que Mastodon usa con altere retes social.\n\nIllo te permitte de connecter te e interager con le personas non solo sur Mastodon, ma alsi inter apps social differente.</string>
<string name="handle_copied">Manico copiate al area de transferentia.</string>
<string name="what_is_activitypub_title">Que es ActivityPub?</string>
<string name="what_is_activitypub">ActivityPub es como le lingua que Mastodon parla con altere retes social.\n\nIllo te permitte connecter te e interager con le personas non solmente sur Mastodon, ma alsi inter apps social differente.</string>
<string name="handle_copied">Pseudonymo copiate al area de transferentia.</string>
<string name="qr_code">Codice QR</string>
<string name="scan_qr_code">Scander codice QR</string>
<string name="scan_qr_code">Scannar codice QR</string>
<!-- Shown on a button that saves a file, after it was successfully saved -->
<string name="saved">Salvate</string>
<string name="image_saved">Imagine salvate.</string>
@@ -698,19 +700,19 @@ Quanto plus personas tu seque, tanto plus active e interessante illo sera.</stri
<string name="share_sheet_preview_profile">%s sur Mastodon</string>
<string name="share_sheet_preview_post">%1$s sur Mastodon: “%2$s”</string>
<string name="copy_profile_link">Copiar ligamine a profilo</string>
<string name="in_app_browser">Navigator in-app</string>
<string name="in_app_browser">Navigator in app</string>
<string name="system_browser">Navigator de systema</string>
<string name="add_muted_word_short">Adder parola</string>
<string name="tab_home">Initio</string>
<string name="tab_search">Explorar</string>
<string name="tab_profile">Profilo</string>
<string name="pin_post">Appunctar sur le profilo</string>
<string name="unpin_post">Distaccar ab le profilo</string>
<string name="post_pinned">Message fixate</string>
<string name="post_unpinned">Le message ha essite distaccate</string>
<string name="pin_post">Fixar sur profilo</string>
<string name="unpin_post">Disfixar del profilo</string>
<string name="post_pinned">Le message ha essite fixate</string>
<string name="post_unpinned">Le message ha essite disfixate</string>
<!-- %s is the username -->
<string name="enable_new_post_notifications">Avisa me quando %s publica un message</string>
<string name="disable_new_post_notifications">Cessa avisar me quando %s publica un message</string>
<string name="enable_new_post_notifications">Notificar me quando %s publica</string>
<string name="disable_new_post_notifications">Non plus notificar me quando %s publica</string>
<string name="new_post_notifications_enabled">Tu recipera notificationes pro nove messages.</string>
<string name="new_post_notifications_disabled">Tu non plus recipera notificationes pro nove messages.</string>
<string name="mute_conversation">Silentiar conversation</string>
@@ -725,8 +727,8 @@ Quanto plus personas tu seque, tanto plus active e interessante illo sera.</stri
<string name="notification_filter_new_accounts">Nove contos</string>
<string name="notification_filter_new_accounts_explanation">Create in le passate 30 dies</string>
<string name="notification_filter_mentions">Mentiones private indesirate</string>
<string name="notification_filter_mentions_explanation">Filtrate salvo que illes es in responsa a tu proprie mention o si tu seque le expeditor</string>
<string name="allow_notifications">Permitter le notificationes</string>
<string name="notification_filter_mentions_explanation">Filtrate, excepte si es in responsa a tu proprie mention o si tu seque le expeditor</string>
<string name="allow_notifications">Permitter notificationes</string>
<string name="mute_notifications">Dimitter petition de aviso</string>
<plurals name="x_people_you_may_know">
<item quantity="one">%,d persona que tu pote cognoscer</item>
@@ -734,17 +736,25 @@ Quanto plus personas tu seque, tanto plus active e interessante illo sera.</stri
</plurals>
<string name="notifications_from_user">Notificationes de %s</string>
<string name="notifications_muted">Le notificationes de %s ha essite dimittite.</string>
<string name="notifications_allowed">%s apparera ora in tu lista del avisos.</string>
<string name="notifications_allowed">%s apparera ora in tu lista de notificationes.</string>
<string name="visibility_subtitle_public">Totes sur e foras de Mastodon</string>
<string name="visibility_subtitle_unlisted">Minus fanfares algorithmic</string>
<string name="visibility_subtitle_followers">Solmente tu sequaces</string>
<string name="visibility_subtitle_followers">Solmente tu sequitores</string>
<string name="visibility_subtitle_private">Tote le personas mentionate in le message</string>
<string name="view_boosts">Vider promovitos</string>
<string name="view_favorites">Vider favoritos</string>
<string name="undo_reblog">Annullar promotion</string>
<string name="undo_favorite">Annullar preferentia</string>
<string name="view_boosts">Vider impulsos</string>
<string name="view_favorites">Vider favorites</string>
<string name="undo_reblog">Disfacer impulso</string>
<string name="undo_favorite">Disfacer favorite</string>
<string name="could_not_reach_server">Impossibile contactar le servitor. Controla tu connexion e retenta?</string>
<string name="connection_timed_out">Le petition exiva del tempore limite. Verifica tu connexion e retenta?</string>
<string name="server_error">Alco errate eveniva parlante con tu servitor. Illo probabilemente non es tu culpa. Retenta?</string>
<string name="not_found">Illo poterea haber essite delite, o forsan illo jammais existeva del toto.</string>
<string name="connection_timed_out">Le requesta ha expirate. Controla tu connexion e retenta.</string>
<string name="server_error">Un error ha occurrite durante le communication con tu servitor. Isto probabilemente non es tu cupla. Retentar?</string>
<string name="not_found">Illo poterea haber essite delite, o forsan illo non ha jammais existite.</string>
<string name="no_servers_found">Necun servitor trovate pro “%s”</string>
<string name="signup_username_taken">Iste nomine de usator es ja prendite. Tenta un altere nomine o &lt;a&gt;elige un altere servitor&lt;/a&gt;.</string>
<string name="signup_email_invalid">Isto non pare como un adresse de e-mail valide.</string>
<string name="signup_email_taken">Le adresse de e-mail es ja in uso. Ha tu &lt;a&gt;oblidate tu contrasigno&lt;/a&gt;?</string>
<plurals name="x_new_notifications">
<item quantity="one">%,d nove notification</item>
<item quantity="other">%,d nove notificationes</item>
</plurals>
</resources>

View File

@@ -260,8 +260,8 @@
<string name="downloading">Atsisiunčiama…</string>
<string name="no_app_to_handle_action">Nėra programėlės šiam veiksmui atlikti</string>
<string name="local_timeline">Vietinis</string>
<string name="trending_posts_info_banner">Tai įrašai, sulaukiantys didžiausio susidomėjimo „Mastodon“ tinkle.</string>
<string name="trending_links_info_banner">Tai naujienos, apie kurias kalbama „Mastodon“ tinkle.</string>
<string name="trending_posts_info_banner">Tai įrašai, sulaukiantys didžiausio susidomėjimo „Mastodon“ platformoje.</string>
<string name="trending_links_info_banner">Tai naujienos, apie kurias kalbama „Mastodon“ platformoje.</string>
<!-- %s is the server domain -->
<string name="local_timeline_info_banner">Tai visų naudotojų įrašai serveryje (%s).</string>
<string name="recommended_accounts_info_banner">Galbūt šios paskyros tau patiks pagal kitas, kurias seki.</string>
@@ -453,7 +453,7 @@
<string name="settings_filters">Filtrai</string>
<string name="settings_server_explanation">Apžvalga, taisyklės, prižiūrėtojai</string>
<!-- %s is the app name (Mastodon, key app_name). I made it a placeholder so everything Just Works™ with forks -->
<string name="about_app">Apie %s</string>
<string name="about_app">Apie %s</string>
<string name="default_post_language">Numatytoji įrašo kalba</string>
<string name="settings_alt_text_reminders">Pridėti alternatyvųjį teksto priminimus</string>
<string name="settings_confirm_unfollow">Klausti prieš atšaukant sekimą kažkam</string>
@@ -598,7 +598,7 @@
<string name="downloading_update">Atsiunčiama (%d%%)</string>
<!-- Shown like a content warning, %s is the name of the filter -->
<string name="post_matches_filter_x">Atitinka filtrą „%s“</string>
<string name="search_mastodon">Ieškoti Mastodon</string>
<string name="search_mastodon">Ieškoti Mastodon</string>
<string name="clear_all">Valyti viską</string>
<string name="search_open_url">Atidaryti URL adresą per „Mastodon“</string>
<string name="posts_matching_hashtag">Įrašai su „%s“</string>
@@ -615,7 +615,7 @@
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Išversta iš %1$s naudojant %2$s</string>
<string name="translation_show_original">Rodyti originalą</string>
<string name="translation_failed">Vertimas nepavyko. Galbūt administratorius (-ė) šiame serveryje neįjungė vertimų arba šiame serveryje veikia senesnė Mastodon versija, kurioje vertimai dar nepalaikomi.</string>
<string name="translation_failed">Vertimas nepavyko. Galbūt administratorius (-ė) šiame serveryje neįjungė vertimų arba šiame serveryje veikia senesnė Mastodon versija, kurioje vertimai dar nepalaikomi.</string>
<string name="settings_privacy">Privatumas ir pasiekiamumas</string>
<string name="settings_discoverable">Rodyti profilį ir įrašus į atradimo algoritmus</string>
<string name="settings_indexable">Įtraukti viešus įrašus į paieškos rezultatus</string>
@@ -754,7 +754,7 @@ Kuo daugiau žmonių seki, tuo aktyvesnis ir įdomesnis jis bus.</string>
<string name="handle_server_explanation_own">Tavo skaitmeniniai namai, kuriuose saugomi visi tavo įrašai. Nepatinka šis? Bet kada perkelk serverius ir atsivesk bei savo sekėjus.</string>
<string name="handle_explanation_own">Kadangi tavo socialinis medijos vardas pasako, kas ir kur esi, žmonės gali bendrauti su tavimi visame socialiniame internete, kurį sudaro &lt;a&gt;„ActivityPub“ veikiančios platformos&lt;/a&gt;.</string>
<string name="what_is_activitypub_title">Kas yra „ActivityPub“?</string>
<string name="what_is_activitypub">„ActivityPub“ tai tarsi kalba, kuria „Mastodon“ kalba su kitais socialiniais tinklais.\n\nTai leidžia tau bendrauti su žmonėmis ne tik „Mastodon“ tinkle, bet ir įvairiose socialinėse programėlėse.</string>
<string name="what_is_activitypub">„ActivityPub“ tai tarsi kalba, kuria „Mastodon“ kalba su kitais socialiniais tinklais.\n\nTai leidžia tau bendrauti su žmonėmis ne tik „Mastodon“ platformoje, bet ir įvairiose socialinėse programėlėse.</string>
<string name="handle_copied">Socialinis medijos vardas nukopijuotas į iškarpinę.</string>
<string name="qr_code">QR kodas</string>
<string name="scan_qr_code">Nuskaityti QR kodą</string>
@@ -763,7 +763,7 @@ Kuo daugiau žmonių seki, tuo aktyvesnis ir įdomesnis jis bus.</string>
<string name="image_saved">Vaizdas išsaugotas.</string>
<string name="video_saved">Vaizdo įrašas išsaugotas.</string>
<string name="view_file">Peržiūrėti</string>
<string name="share_sheet_preview_profile">%s, būnant Mastodon</string>
<string name="share_sheet_preview_profile">%s, platformoje „Mastodon</string>
<string name="share_sheet_preview_post">%1$s, platformoje „Mastodon“: %2$s</string>
<string name="copy_profile_link">Kopijuoti nuorodą į profilį</string>
<string name="in_app_browser">Naršyklė programėlėje</string>
@@ -814,7 +814,7 @@ Kuo daugiau žmonių seki, tuo aktyvesnis ir įdomesnis jis bus.</string>
<string name="undo_reblog">Atšaukti pasidalinimą</string>
<string name="undo_favorite">Panaikinti mėgstamą</string>
<string name="could_not_reach_server">Nepavyko pasiekti serverio. Patikrinti ryšį ir bandyti dar kartą?</string>
<string name="connection_timed_out">Užklausa užtruko. Patikrinti ryšį ir bandyti dar kartą?</string>
<string name="connection_timed_out">Užklausai baigėsi laikas. Patikrinti ryšį ir bandyti dar kartą?</string>
<string name="server_error">Kažkas nepavyko susikalbėti su serveriu. Tikriausiai tai ne tavo kaltė. Bandyti dar kartą?</string>
<string name="not_found">Jis galėjo būti ištrintas, o gal išvis niekada neegzistavo.</string>
<string name="no_servers_found">Nerasta serverių „%s“</string>

View File

@@ -307,13 +307,16 @@
<string name="instance_signup_closed">Deze server accepteert geen nieuwe registraties.</string>
<string name="text_copied">Gekopieerd naar klembord</string>
<string name="add_bookmark">Bladwijzer toevoegen</string>
<string name="remove_bookmark">Bladwijzer verwijderen</string>
<string name="bookmarks">Bladwijzers</string>
<string name="your_favorites">Jouw favorieten</string>
<string name="login_title">Welkom terug</string>
<string name="login_subtitle">Bij de server waar je je account hebt aangemaakt inloggen.</string>
<string name="server_url">Server-URL</string>
<string name="server_filter_any_language">Elke taal</string>
<string name="server_filter_instant_signup">Direct registreren</string>
<string name="server_filter_manual_review">Handmatige beoordeling nodig</string>
<string name="server_filter_any_signup_speed">Elke registratiesnelheid</string>
<string name="server_filter_region_europe">Europa</string>
<string name="server_filter_region_north_america">Noord-Amerika</string>
<string name="server_filter_region_south_america">Zuid-Amerika</string>
@@ -516,7 +519,7 @@
<string name="edit_muted_word">Genegeerd woord bewerken</string>
<string name="add">Toevoegen</string>
<string name="filter_word_or_phrase">Woord of zinsdeel</string>
<string name="filter_add_word_help">Woorden zijn niet hoofdlettergevoelig en komen alleen overeen met volledige woorden.\n\nWanneer je op de term Appel filtert, verbergt het berichten die appel of aPpEl bevatten, maar niet ananas.</string>
<string name="filter_add_word_help">Woorden zijn niet hoofdlettergevoelig en komen alleen overeen met volledige woorden.\n\nWanneer je op de term Appel filtert, worden berichten verborgen die appel of aPpEl bevatten, maar niet sinaasappel.</string>
<string name="settings_delete_filter_word">%s verwijderen?</string>
<string name="enter_selection_mode">Selecteren</string>
<string name="select_all">Alles selecteren</string>
@@ -731,10 +734,26 @@
<item quantity="other">%,d mensen die je misschien kent</item>
</plurals>
<string name="notifications_from_user">Meldingen van %s</string>
<string name="notifications_muted">Notifications from %s zijn afgewezen.</string>
<string name="notifications_muted">Meldingen van %s zijn afgewezen.</string>
<string name="notifications_allowed">%s verschijnt vanaf nu onder jouw meldingen.</string>
<string name="visibility_subtitle_public">Iedereen op Mastodon en daarbuiten</string>
<string name="visibility_subtitle_unlisted">Voor iedereen zichtbaar, maar niet onder trends, hashtags en op openbare tijdlijnen</string>
<string name="visibility_subtitle_followers">Alleen jouw volgers</string>
<string name="visibility_subtitle_private">Alleen voor mensen die specifiek in het bericht worden vermeld</string>
<string name="view_boosts">Boosts bekijken</string>
<string name="view_favorites">Favorieten bekijken</string>
<string name="undo_reblog">Boost ongedaan maken</string>
<string name="undo_favorite">Favoriet ongedaan maken</string>
<string name="could_not_reach_server">Kon de server niet bereiken. Controleer je verbinding en probeer het opnieuw.</string>
<string name="connection_timed_out">De aanvraag is verlopen. Controleer je verbinding en probeer het opnieuw.</string>
<string name="server_error">Er is iets misgegaan met de communicatie met je server. Waarschijnlijk is het niet jouw fout. Opnieuw proberen?</string>
<string name="not_found">Deze is wellicht verwijderd of heeft misschien nooit bestaan.</string>
<string name="no_servers_found">Geen servers gevonden voor “%s”</string>
<string name="signup_username_taken">Deze gebruikersnaam is al in gebruik. Probeer een andere gebruikersnaam of &lt;a&gt;kies een andere server&lt;/a&gt;.</string>
<string name="signup_email_invalid">Dat lijkt geen geldig e-mailadres te zijn.</string>
<string name="signup_email_taken">Dat e-mailadres is al in gebruik. Ben je misschien &lt;a&gt;je wachtwoord vergeten&lt;/a&gt;?</string>
<plurals name="x_new_notifications">
<item quantity="one">%,d nieuwe melding</item>
<item quantity="other">%,d nieuwe meldingen</item>
</plurals>
</resources>

View File

@@ -743,4 +743,16 @@ Quanto mais pessoas que você seguir, mas interessantes e ativas serão.</string
<string name="view_favorites">Visualizar favoritos</string>
<string name="undo_reblog">Desfazer boost</string>
<string name="undo_favorite">Desfazer favorito</string>
<string name="could_not_reach_server">Não foi possível acessar o servidor. Verifique sua conexão e tente novamente?</string>
<string name="connection_timed_out">O pedido expirou. Verifique sua conexão e tente novamente?</string>
<string name="server_error">Algo deu errado ao falar com o seu servidor. Provavelmente não é culpa sua. Tentar novamente?</string>
<string name="not_found">Ele pode ter sido deletado, ou talvez nunca tenha existido.</string>
<string name="no_servers_found">Nenhum servidor encontrado para “%s”</string>
<string name="signup_username_taken">Este nome de usuário já foi usado. Tente usar outro ou &lt;a&gt;escolha um servidor diferente&lt;/a&gt;.</string>
<string name="signup_email_invalid">Este não parece ser um endereço de e-mail válido.</string>
<string name="signup_email_taken">O endereço de e-mail já está em uso. Você &lt;a&gt;esqueceu sua senha&lt;/a&gt;?</string>
<plurals name="x_new_notifications">
<item quantity="one">%,d nova notificação</item>
<item quantity="other">%,d novas notificações</item>
</plurals>
</resources>

View File

@@ -9,6 +9,7 @@
<string name="preparing_auth">Подготовка к авторизации…</string>
<string name="finishing_auth">Завершение авторизации…</string>
<string name="user_boosted">%s продвинул(а)</string>
<string name="in_reply_to">в ответ %s</string>
<string name="notifications">Уведомления</string>
<string name="user_followed_you">%s подписался(ась) на вас</string>
<string name="user_sent_follow_request">%s отправил(а) вам запрос на подписку</string>
@@ -188,6 +189,8 @@
<string name="save">Сохранить</string>
<string name="add_alt_text">Добавить альтернативный текст</string>
<string name="visibility_public">Публичный</string>
<string name="visibility_followers_only">Читатели</string>
<string name="visibility_private">Определённые люди</string>
<string name="recent_searches">Недавние</string>
<string name="skip">Пропустить</string>
<string name="notification_type_follow">Новые подписчики</string>
@@ -342,6 +345,7 @@
<string name="instance_signup_closed">Этот сервер не принимает новые регистрации.</string>
<string name="text_copied">Скопировано в буфер обмена</string>
<string name="add_bookmark">Закладка</string>
<string name="remove_bookmark">Удалить закладку</string>
<string name="bookmarks">Закладки</string>
<string name="your_favorites">Ваше избранное</string>
<string name="login_title">С возвращением</string>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="hundred_dp">133</integer>
</resources>

View File

@@ -352,7 +352,9 @@
<string name="login_subtitle">Увійдіть за допомогою сервера, де ви створили свій обліковий запис.</string>
<string name="server_url">URL-адреса сервера</string>
<string name="server_filter_any_language">Будь-яка мова</string>
<string name="server_filter_instant_signup">Миттєва реєстрація</string>
<string name="server_filter_manual_review">Ручна перевірка</string>
<string name="server_filter_any_signup_speed">Будь-яка швидкість реєстрації</string>
<string name="server_filter_region_europe">Європа</string>
<string name="server_filter_region_north_america">Північна Америка</string>
<string name="server_filter_region_south_america">Південна Америка</string>
@@ -781,4 +783,30 @@
<string name="notification_filter_following">Люди, на яких ви не підписані</string>
<string name="notification_filter_following_explanation">Доки ви не схвалюєте їх вручну</string>
<string name="notification_filter_followers">Люди, які не підписані на вас</string>
<string name="notification_filter_followers_explanation">Включаючи людей, які підписані на вас менш ніж три дні</string>
<string name="notification_filter_new_accounts">Нові облікові записи</string>
<string name="notification_filter_new_accounts_explanation">Створені за останні 30 днів</string>
<string name="notification_filter_mentions">Небажані приватні згадки</string>
<string name="notification_filter_mentions_explanation">Відфільтровується, якщо це не відповідь на вашу власну згадку або якщо ви відстежуєте відправника</string>
<string name="allow_notifications">Дозволити сповіщення</string>
<string name="mute_notifications">Відхилити запит на сповіщення</string>
<string name="notifications_from_user">Сповіщення від %s</string>
<string name="notifications_muted">Сповіщення від %s було відхилено.</string>
<string name="notifications_allowed">%s тепер з\'явиться у вашому списку сповіщень.</string>
<string name="visibility_subtitle_public">Усі з Mastodon та поза Mastodon</string>
<string name="visibility_subtitle_unlisted">Менше алгоритмічних фанфар</string>
<string name="visibility_subtitle_followers">Лише ваші підписники</string>
<string name="visibility_subtitle_private">Усі згадані в дописі</string>
<string name="view_boosts">Переглянути поширення</string>
<string name="view_favorites">Подивитися обране</string>
<string name="undo_reblog">Скасувати поширення</string>
<string name="undo_favorite">Скасувати вибране</string>
<string name="could_not_reach_server">Не вдалося зв\'язатися з сервером. Перевірте підключення та повторіть спробу?</string>
<string name="connection_timed_out">Час очікування запиту минув. Перевірте підключення і повторіть спробу?</string>
<string name="server_error">Щось пішло не так при спілкуванні з вашим сервером. Це, скоріше за все, не ваша помилка. Спробувати ще раз?</string>
<string name="not_found">Можливо, його видалили, або його взагалі ніколи не існувало.</string>
<string name="no_servers_found">Не знайдено серверів для \"%s\"</string>
<string name="signup_username_taken">Це ім\'я вже зайнято. Спробуйте інше, або &lt;a&gt;оберіть інший сервер&lt;/a&gt;.</string>
<string name="signup_email_invalid">Це не схоже на дійсну адресу електронної пошти.</string>
<string name="signup_email_taken">Адреса пошти вже використана. Ви &lt;a&gt;забули ваш пароль&lt;/a&gt;?</string>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="hundred_dp">200</integer>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="hundred_dp">300</integer>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="hundred_dp">400</integer>
</resources>

View File

@@ -0,0 +1,336 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- light -->
<color name="masterialLight_primary">#4000DD</color>
<color name="masterialLight_onPrimary">#FFFFFF</color>
<color name="masterialLight_primaryContainer">#6648FF</color>
<color name="masterialLight_onPrimaryContainer">#FFFFFF</color>
<color name="masterialLight_secondary">#5D51AF</color>
<color name="masterialLight_onSecondary">#FFFFFF</color>
<color name="masterialLight_secondaryContainer">#B0A5FF</color>
<color name="masterialLight_onSecondaryContainer">#220C73</color>
<color name="masterialLight_tertiary">#810082</color>
<color name="masterialLight_onTertiary">#FFFFFF</color>
<color name="masterialLight_tertiaryContainer">#B722B7</color>
<color name="masterialLight_onTertiaryContainer">#FFFFFF</color>
<color name="masterialLight_error">#BA1A1A</color>
<color name="masterialLight_onError">#FFFFFF</color>
<color name="masterialLight_errorContainer">#FFDAD6</color>
<color name="masterialLight_onErrorContainer">#410002</color>
<color name="masterialLight_background">#FCF8FF</color>
<color name="masterialLight_onBackground">#1C1A25</color>
<color name="masterialLight_surface">#FCF8FF</color>
<color name="masterialLight_onSurface">#1C1A25</color>
<color name="masterialLight_surfaceVariant">#E5DFF6</color>
<color name="masterialLight_onSurfaceVariant">#474557</color>
<color name="masterialLight_outline">#787588</color>
<color name="masterialLight_outlineVariant">#C9C4DA</color>
<color name="masterialLight_scrim">#000000</color>
<color name="masterialLight_inverseSurface">#312F3B</color>
<color name="masterialLight_inverseOnSurface">#F3EEFE</color>
<color name="masterialLight_inversePrimary">#C7BFFF</color>
<color name="masterialLight_primaryFixed">#E5DEFF</color>
<color name="masterialLight_onPrimaryFixed">#180065</color>
<color name="masterialLight_primaryFixedDim">#C7BFFF</color>
<color name="masterialLight_onPrimaryFixedVariant">#4000DC</color>
<color name="masterialLight_secondaryFixed">#E5DEFF</color>
<color name="masterialLight_onSecondaryFixed">#180065</color>
<color name="masterialLight_secondaryFixedDim">#C7BFFF</color>
<color name="masterialLight_onSecondaryFixedVariant">#453895</color>
<color name="masterialLight_tertiaryFixed">#FFD7F6</color>
<color name="masterialLight_onTertiaryFixed">#380039</color>
<color name="masterialLight_tertiaryFixedDim">#FFAAF5</color>
<color name="masterialLight_onTertiaryFixedVariant">#800082</color>
<color name="masterialLight_surfaceDim">#DCD8E7</color>
<color name="masterialLight_surfaceBright">#FCF8FF</color>
<color name="masterialLight_surfaceContainerLowest">#FFFFFF</color>
<color name="masterialLight_surfaceContainerLow">#F6F1FF</color>
<color name="masterialLight_surfaceContainer">#F1EBFB</color>
<color name="masterialLight_surfaceContainerHigh">#EBE6F6</color>
<color name="masterialLight_surfaceContainerHighest">#E5E0F0</color>
<color name="masterialLight_primary_mediumContrast">#3C00D1</color>
<color name="masterialLight_onPrimary_mediumContrast">#FFFFFF</color>
<color name="masterialLight_primaryContainer_mediumContrast">#6648FF</color>
<color name="masterialLight_onPrimaryContainer_mediumContrast">#FFFFFF</color>
<color name="masterialLight_secondary_mediumContrast">#413391</color>
<color name="masterialLight_onSecondary_mediumContrast">#FFFFFF</color>
<color name="masterialLight_secondaryContainer_mediumContrast">#7368C7</color>
<color name="masterialLight_onSecondaryContainer_mediumContrast">#FFFFFF</color>
<color name="masterialLight_tertiary_mediumContrast">#7A007B</color>
<color name="masterialLight_onTertiary_mediumContrast">#FFFFFF</color>
<color name="masterialLight_tertiaryContainer_mediumContrast">#B722B7</color>
<color name="masterialLight_onTertiaryContainer_mediumContrast">#FFFFFF</color>
<color name="masterialLight_error_mediumContrast">#8C0009</color>
<color name="masterialLight_onError_mediumContrast">#FFFFFF</color>
<color name="masterialLight_errorContainer_mediumContrast">#DA342E</color>
<color name="masterialLight_onErrorContainer_mediumContrast">#FFFFFF</color>
<color name="masterialLight_background_mediumContrast">#FCF8FF</color>
<color name="masterialLight_onBackground_mediumContrast">#1C1A25</color>
<color name="masterialLight_surface_mediumContrast">#FCF8FF</color>
<color name="masterialLight_onSurface_mediumContrast">#1C1A25</color>
<color name="masterialLight_surfaceVariant_mediumContrast">#E5DFF6</color>
<color name="masterialLight_onSurfaceVariant_mediumContrast">#434153</color>
<color name="masterialLight_outline_mediumContrast">#605D70</color>
<color name="masterialLight_outlineVariant_mediumContrast">#7C788C</color>
<color name="masterialLight_scrim_mediumContrast">#000000</color>
<color name="masterialLight_inverseSurface_mediumContrast">#312F3B</color>
<color name="masterialLight_inverseOnSurface_mediumContrast">#F3EEFE</color>
<color name="masterialLight_inversePrimary_mediumContrast">#C7BFFF</color>
<color name="masterialLight_primaryFixed_mediumContrast">#7058FF</color>
<color name="masterialLight_onPrimaryFixed_mediumContrast">#FFFFFF</color>
<color name="masterialLight_primaryFixedDim_mediumContrast">#552BFB</color>
<color name="masterialLight_onPrimaryFixedVariant_mediumContrast">#FFFFFF</color>
<color name="masterialLight_secondaryFixed_mediumContrast">#7368C7</color>
<color name="masterialLight_onSecondaryFixed_mediumContrast">#FFFFFF</color>
<color name="masterialLight_secondaryFixedDim_mediumContrast">#5A4EAC</color>
<color name="masterialLight_onSecondaryFixedVariant_mediumContrast">#FFFFFF</color>
<color name="masterialLight_tertiaryFixed_mediumContrast">#C330C2</color>
<color name="masterialLight_onTertiaryFixed_mediumContrast">#FFFFFF</color>
<color name="masterialLight_tertiaryFixedDim_mediumContrast">#A400A6</color>
<color name="masterialLight_onTertiaryFixedVariant_mediumContrast">#FFFFFF</color>
<color name="masterialLight_surfaceDim_mediumContrast">#DCD8E7</color>
<color name="masterialLight_surfaceBright_mediumContrast">#FCF8FF</color>
<color name="masterialLight_surfaceContainerLowest_mediumContrast">#FFFFFF</color>
<color name="masterialLight_surfaceContainerLow_mediumContrast">#F6F1FF</color>
<color name="masterialLight_surfaceContainer_mediumContrast">#F1EBFB</color>
<color name="masterialLight_surfaceContainerHigh_mediumContrast">#EBE6F6</color>
<color name="masterialLight_surfaceContainerHighest_mediumContrast">#E5E0F0</color>
<color name="masterialLight_primary_highContrast">#1E0077</color>
<color name="masterialLight_onPrimary_highContrast">#FFFFFF</color>
<color name="masterialLight_primaryContainer_highContrast">#3C00D1</color>
<color name="masterialLight_onPrimaryContainer_highContrast">#FFFFFF</color>
<color name="masterialLight_secondary_highContrast">#1F0671</color>
<color name="masterialLight_onSecondary_highContrast">#FFFFFF</color>
<color name="masterialLight_secondaryContainer_highContrast">#413391</color>
<color name="masterialLight_onSecondaryContainer_highContrast">#FFFFFF</color>
<color name="masterialLight_tertiary_highContrast">#430044</color>
<color name="masterialLight_onTertiary_highContrast">#FFFFFF</color>
<color name="masterialLight_tertiaryContainer_highContrast">#7A007B</color>
<color name="masterialLight_onTertiaryContainer_highContrast">#FFFFFF</color>
<color name="masterialLight_error_highContrast">#4E0002</color>
<color name="masterialLight_onError_highContrast">#FFFFFF</color>
<color name="masterialLight_errorContainer_highContrast">#8C0009</color>
<color name="masterialLight_onErrorContainer_highContrast">#FFFFFF</color>
<color name="masterialLight_background_highContrast">#FCF8FF</color>
<color name="masterialLight_onBackground_highContrast">#1C1A25</color>
<color name="masterialLight_surface_highContrast">#FCF8FF</color>
<color name="masterialLight_onSurface_highContrast">#000000</color>
<color name="masterialLight_surfaceVariant_highContrast">#E5DFF6</color>
<color name="masterialLight_onSurfaceVariant_highContrast">#242232</color>
<color name="masterialLight_outline_highContrast">#434153</color>
<color name="masterialLight_outlineVariant_highContrast">#434153</color>
<color name="masterialLight_scrim_highContrast">#000000</color>
<color name="masterialLight_inverseSurface_highContrast">#312F3B</color>
<color name="masterialLight_inverseOnSurface_highContrast">#FFFFFF</color>
<color name="masterialLight_inversePrimary_highContrast">#EFE9FF</color>
<color name="masterialLight_primaryFixed_highContrast">#3C00D1</color>
<color name="masterialLight_onPrimaryFixed_highContrast">#FFFFFF</color>
<color name="masterialLight_primaryFixedDim_highContrast">#280094</color>
<color name="masterialLight_onPrimaryFixedVariant_highContrast">#FFFFFF</color>
<color name="masterialLight_secondaryFixed_highContrast">#413391</color>
<color name="masterialLight_onSecondaryFixed_highContrast">#FFFFFF</color>
<color name="masterialLight_secondaryFixedDim_highContrast">#2A197A</color>
<color name="masterialLight_onSecondaryFixedVariant_highContrast">#FFFFFF</color>
<color name="masterialLight_tertiaryFixed_highContrast">#7A007B</color>
<color name="masterialLight_onTertiaryFixed_highContrast">#FFFFFF</color>
<color name="masterialLight_tertiaryFixedDim_highContrast">#550056</color>
<color name="masterialLight_onTertiaryFixedVariant_highContrast">#FFFFFF</color>
<color name="masterialLight_surfaceDim_highContrast">#DCD8E7</color>
<color name="masterialLight_surfaceBright_highContrast">#FCF8FF</color>
<color name="masterialLight_surfaceContainerLowest_highContrast">#FFFFFF</color>
<color name="masterialLight_surfaceContainerLow_highContrast">#F6F1FF</color>
<color name="masterialLight_surfaceContainer_highContrast">#F1EBFB</color>
<color name="masterialLight_surfaceContainerHigh_highContrast">#EBE6F6</color>
<color name="masterialLight_surfaceContainerHighest_highContrast">#E5E0F0</color>
<color name="masterialLight_colorGoldenrod">#7B5800</color>
<color name="masterialLight_colorOnGoldenrod">#FFFFFF</color>
<color name="masterialLight_colorGoldenrodContainer">#FFC758</color>
<color name="masterialLight_colorOnGoldenrodContainer">#503800</color>
<color name="masterialLight_colorLime">#476800</color>
<color name="masterialLight_colorOnLime">#FFFFFF</color>
<color name="masterialLight_colorLimeContainer">#CAFF71</color>
<color name="masterialLight_colorOnLimeContainer">#3A5700</color>
<color name="masterialLight_colorGoldenrod_mediumContrast">#583E00</color>
<color name="masterialLight_colorOnGoldenrod_mediumContrast">#FFFFFF</color>
<color name="masterialLight_colorGoldenrodContainer_mediumContrast">#986D00</color>
<color name="masterialLight_colorOnGoldenrodContainer_mediumContrast">#FFFFFF</color>
<color name="masterialLight_colorLime_mediumContrast">#314A00</color>
<color name="masterialLight_colorOnLime_mediumContrast">#FFFFFF</color>
<color name="masterialLight_colorLimeContainer_mediumContrast">#588000</color>
<color name="masterialLight_colorOnLimeContainer_mediumContrast">#FFFFFF</color>
<color name="masterialLight_colorGoldenrod_highContrast">#2F1F00</color>
<color name="masterialLight_colorOnGoldenrod_highContrast">#FFFFFF</color>
<color name="masterialLight_colorGoldenrodContainer_highContrast">#583E00</color>
<color name="masterialLight_colorOnGoldenrodContainer_highContrast">#FFFFFF</color>
<color name="masterialLight_colorLime_highContrast">#182600</color>
<color name="masterialLight_colorOnLime_highContrast">#FFFFFF</color>
<color name="masterialLight_colorLimeContainer_highContrast">#314A00</color>
<color name="masterialLight_colorOnLimeContainer_highContrast">#FFFFFF</color>
<!-- dark -->
<color name="masterialDark_primary">#C7BFFF</color>
<color name="masterialDark_onPrimary">#2B009E</color>
<color name="masterialDark_primaryContainer">#4D1AF4</color>
<color name="masterialDark_onPrimaryContainer">#FAF5FF</color>
<color name="masterialDark_secondary">#C7BFFF</color>
<color name="masterialDark_onSecondary">#2E1E7E</color>
<color name="masterialDark_secondaryContainer">#3D308E</color>
<color name="masterialDark_onSecondaryContainer">#D6CFFF</color>
<color name="masterialDark_tertiary">#FFAAF5</color>
<color name="masterialDark_onTertiary">#5B005C</color>
<color name="masterialDark_tertiaryContainer">#970099</color>
<color name="masterialDark_onTertiaryContainer">#FFF5F9</color>
<color name="masterialDark_error">#FFB4AB</color>
<color name="masterialDark_onError">#690005</color>
<color name="masterialDark_errorContainer">#93000A</color>
<color name="masterialDark_onErrorContainer">#FFDAD6</color>
<color name="masterialDark_background">#13121D</color>
<color name="masterialDark_onBackground">#E5E0F0</color>
<color name="masterialDark_surface">#13121D</color>
<color name="masterialDark_onSurface">#E5E0F0</color>
<color name="masterialDark_surfaceVariant">#474557</color>
<color name="masterialDark_onSurfaceVariant">#C9C4DA</color>
<color name="masterialDark_outline">#928EA3</color>
<color name="masterialDark_outlineVariant">#474557</color>
<color name="masterialDark_scrim">#000000</color>
<color name="masterialDark_inverseSurface">#E5E0F0</color>
<color name="masterialDark_inverseOnSurface">#312F3B</color>
<color name="masterialDark_inversePrimary">#582FFE</color>
<color name="masterialDark_primaryFixed">#E5DEFF</color>
<color name="masterialDark_onPrimaryFixed">#180065</color>
<color name="masterialDark_primaryFixedDim">#C7BFFF</color>
<color name="masterialDark_onPrimaryFixedVariant">#4000DC</color>
<color name="masterialDark_secondaryFixed">#E5DEFF</color>
<color name="masterialDark_onSecondaryFixed">#180065</color>
<color name="masterialDark_secondaryFixedDim">#C7BFFF</color>
<color name="masterialDark_onSecondaryFixedVariant">#453895</color>
<color name="masterialDark_tertiaryFixed">#FFD7F6</color>
<color name="masterialDark_onTertiaryFixed">#380039</color>
<color name="masterialDark_tertiaryFixedDim">#FFAAF5</color>
<color name="masterialDark_onTertiaryFixedVariant">#800082</color>
<color name="masterialDark_surfaceDim">#13121D</color>
<color name="masterialDark_surfaceBright">#3A3844</color>
<color name="masterialDark_surfaceContainerLowest">#0E0D17</color>
<color name="masterialDark_surfaceContainerLow">#1C1A25</color>
<color name="masterialDark_surfaceContainer">#201E29</color>
<color name="masterialDark_surfaceContainerHigh">#2A2934</color>
<color name="masterialDark_surfaceContainerHighest">#35333F</color>
<color name="masterialDark_primary_mediumContrast">#CCC4FF</color>
<color name="masterialDark_onPrimary_mediumContrast">#130056</color>
<color name="masterialDark_primaryContainer_mediumContrast">#8F7FFF</color>
<color name="masterialDark_onPrimaryContainer_mediumContrast">#000000</color>
<color name="masterialDark_secondary_mediumContrast">#CCC4FF</color>
<color name="masterialDark_onSecondary_mediumContrast">#130056</color>
<color name="masterialDark_secondaryContainer_mediumContrast">#9084E6</color>
<color name="masterialDark_onSecondaryContainer_mediumContrast">#000000</color>
<color name="masterialDark_tertiary_mediumContrast">#FFB1F5</color>
<color name="masterialDark_onTertiary_mediumContrast">#2F0030</color>
<color name="masterialDark_tertiaryContainer_mediumContrast">#E552E1</color>
<color name="masterialDark_onTertiaryContainer_mediumContrast">#000000</color>
<color name="masterialDark_error_mediumContrast">#FFBAB1</color>
<color name="masterialDark_onError_mediumContrast">#370001</color>
<color name="masterialDark_errorContainer_mediumContrast">#FF5449</color>
<color name="masterialDark_onErrorContainer_mediumContrast">#000000</color>
<color name="masterialDark_background_mediumContrast">#13121D</color>
<color name="masterialDark_onBackground_mediumContrast">#E5E0F0</color>
<color name="masterialDark_surface_mediumContrast">#13121D</color>
<color name="masterialDark_onSurface_mediumContrast">#FEF9FF</color>
<color name="masterialDark_surfaceVariant_mediumContrast">#474557</color>
<color name="masterialDark_onSurfaceVariant_mediumContrast">#CDC8DE</color>
<color name="masterialDark_outline_mediumContrast">#A4A0B5</color>
<color name="masterialDark_outlineVariant_mediumContrast">#848195</color>
<color name="masterialDark_scrim_mediumContrast">#000000</color>
<color name="masterialDark_inverseSurface_mediumContrast">#E5E0F0</color>
<color name="masterialDark_inverseOnSurface_mediumContrast">#2A2934</color>
<color name="masterialDark_inversePrimary_mediumContrast">#4100DF</color>
<color name="masterialDark_primaryFixed_mediumContrast">#E5DEFF</color>
<color name="masterialDark_onPrimaryFixed_mediumContrast">#0F0048</color>
<color name="masterialDark_primaryFixedDim_mediumContrast">#C7BFFF</color>
<color name="masterialDark_onPrimaryFixedVariant_mediumContrast">#3000AE</color>
<color name="masterialDark_secondaryFixed_mediumContrast">#E5DEFF</color>
<color name="masterialDark_onSecondaryFixed_mediumContrast">#0F0048</color>
<color name="masterialDark_secondaryFixedDim_mediumContrast">#C7BFFF</color>
<color name="masterialDark_onSecondaryFixedVariant_mediumContrast">#342584</color>
<color name="masterialDark_tertiaryFixed_mediumContrast">#FFD7F6</color>
<color name="masterialDark_onTertiaryFixed_mediumContrast">#260027</color>
<color name="masterialDark_tertiaryFixedDim_mediumContrast">#FFAAF5</color>
<color name="masterialDark_onTertiaryFixedVariant_mediumContrast">#650066</color>
<color name="masterialDark_surfaceDim_mediumContrast">#13121D</color>
<color name="masterialDark_surfaceBright_mediumContrast">#3A3844</color>
<color name="masterialDark_surfaceContainerLowest_mediumContrast">#0E0D17</color>
<color name="masterialDark_surfaceContainerLow_mediumContrast">#1C1A25</color>
<color name="masterialDark_surfaceContainer_mediumContrast">#201E29</color>
<color name="masterialDark_surfaceContainerHigh_mediumContrast">#2A2934</color>
<color name="masterialDark_surfaceContainerHighest_mediumContrast">#35333F</color>
<color name="masterialDark_primary_highContrast">#FEF9FF</color>
<color name="masterialDark_onPrimary_highContrast">#000000</color>
<color name="masterialDark_primaryContainer_highContrast">#CCC4FF</color>
<color name="masterialDark_onPrimaryContainer_highContrast">#000000</color>
<color name="masterialDark_secondary_highContrast">#FEF9FF</color>
<color name="masterialDark_onSecondary_highContrast">#000000</color>
<color name="masterialDark_secondaryContainer_highContrast">#CCC4FF</color>
<color name="masterialDark_onSecondaryContainer_highContrast">#000000</color>
<color name="masterialDark_tertiary_highContrast">#FFF9FA</color>
<color name="masterialDark_onTertiary_highContrast">#000000</color>
<color name="masterialDark_tertiaryContainer_highContrast">#FFB1F5</color>
<color name="masterialDark_onTertiaryContainer_highContrast">#000000</color>
<color name="masterialDark_error_highContrast">#FFF9F9</color>
<color name="masterialDark_onError_highContrast">#000000</color>
<color name="masterialDark_errorContainer_highContrast">#FFBAB1</color>
<color name="masterialDark_onErrorContainer_highContrast">#000000</color>
<color name="masterialDark_background_highContrast">#13121D</color>
<color name="masterialDark_onBackground_highContrast">#E5E0F0</color>
<color name="masterialDark_surface_highContrast">#13121D</color>
<color name="masterialDark_onSurface_highContrast">#FFFFFF</color>
<color name="masterialDark_surfaceVariant_highContrast">#474557</color>
<color name="masterialDark_onSurfaceVariant_highContrast">#FEF9FF</color>
<color name="masterialDark_outline_highContrast">#CDC8DE</color>
<color name="masterialDark_outlineVariant_highContrast">#CDC8DE</color>
<color name="masterialDark_scrim_highContrast">#000000</color>
<color name="masterialDark_inverseSurface_highContrast">#E5E0F0</color>
<color name="masterialDark_inverseOnSurface_highContrast">#000000</color>
<color name="masterialDark_inversePrimary_highContrast">#25008C</color>
<color name="masterialDark_primaryFixed_highContrast">#E9E3FF</color>
<color name="masterialDark_onPrimaryFixed_highContrast">#000000</color>
<color name="masterialDark_primaryFixedDim_highContrast">#CCC4FF</color>
<color name="masterialDark_onPrimaryFixedVariant_highContrast">#130056</color>
<color name="masterialDark_secondaryFixed_highContrast">#E9E3FF</color>
<color name="masterialDark_onSecondaryFixed_highContrast">#000000</color>
<color name="masterialDark_secondaryFixedDim_highContrast">#CCC4FF</color>
<color name="masterialDark_onSecondaryFixedVariant_highContrast">#130056</color>
<color name="masterialDark_tertiaryFixed_highContrast">#FFDDF6</color>
<color name="masterialDark_onTertiaryFixed_highContrast">#000000</color>
<color name="masterialDark_tertiaryFixedDim_highContrast">#FFB1F5</color>
<color name="masterialDark_onTertiaryFixedVariant_highContrast">#2F0030</color>
<color name="masterialDark_surfaceDim_highContrast">#13121D</color>
<color name="masterialDark_surfaceBright_highContrast">#3A3844</color>
<color name="masterialDark_surfaceContainerLowest_highContrast">#0E0D17</color>
<color name="masterialDark_surfaceContainerLow_highContrast">#1C1A25</color>
<color name="masterialDark_surfaceContainer_highContrast">#201E29</color>
<color name="masterialDark_surfaceContainerHigh_highContrast">#2A2934</color>
<color name="masterialDark_surfaceContainerHighest_highContrast">#35333F</color>
<color name="masterialDark_colorGoldenrod">#FFEBCE</color>
<color name="masterialDark_colorOnGoldenrod">#412D00</color>
<color name="masterialDark_colorGoldenrodContainer">#F9B928</color>
<color name="masterialDark_colorOnGoldenrodContainer">#463100</color>
<color name="masterialDark_colorLime">#FFFFFF</color>
<color name="masterialDark_colorOnLime">#233600</color>
<color name="masterialDark_colorLimeContainer">#A5E820</color>
<color name="masterialDark_colorOnLimeContainer">#2E4600</color>
<color name="masterialDark_colorGoldenrod_mediumContrast">#FFEBCE</color>
<color name="masterialDark_colorOnGoldenrod_mediumContrast">#412D00</color>
<color name="masterialDark_colorGoldenrodContainer_mediumContrast">#F9B928</color>
<color name="masterialDark_colorOnGoldenrodContainer_mediumContrast">#150C00</color>
<color name="masterialDark_colorLime_mediumContrast">#FFFFFF</color>
<color name="masterialDark_colorOnLime_mediumContrast">#233600</color>
<color name="masterialDark_colorLimeContainer_mediumContrast">#A5E820</color>
<color name="masterialDark_colorOnLimeContainer_mediumContrast">#162300</color>
<color name="masterialDark_colorGoldenrod_highContrast">#FFFAF7</color>
<color name="masterialDark_colorOnGoldenrod_highContrast">#000000</color>
<color name="masterialDark_colorGoldenrodContainer_highContrast">#FFC03B</color>
<color name="masterialDark_colorOnGoldenrodContainer_highContrast">#000000</color>
<color name="masterialDark_colorLime_highContrast">#FFFFFF</color>
<color name="masterialDark_colorOnLime_highContrast">#000000</color>
<color name="masterialDark_colorLimeContainer_highContrast">#A5E820</color>
<color name="masterialDark_colorOnLimeContainer_highContrast">#000000</color>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="hundred_dp">100</integer>
</resources>

View File

@@ -766,4 +766,15 @@
<item quantity="one">%,d new notification</item>
<item quantity="other">%,d new notifications</item>
</plurals>
<string name="dismiss">Dismiss</string>
<string name="donation_once">Just once</string>
<string name="donation_monthly">Monthly</string>
<string name="donation_yearly">Yearly</string>
<string name="currency">Currency</string>
<string name="donation_success_share">Spread the word</string>
<string name="donation_success_title">Thank you for your contribution!</string>
<string name="donation_success_subtitle">You should receive an email confirming your donation soon.</string>
<string name="donation_server_error">We are sorry, an error occurred and we have not been able to process your donation.\n\nPlease retry in a few minutes.</string>
<string name="settings_donate">Donate to Mastodon</string>
<string name="settings_manage_donations">Manage donations</string>
</resources>