Merge branch 'develop'

This commit is contained in:
stom79 2018-01-20 11:22:12 +01:00
commit f725581aef
58 changed files with 938 additions and 163 deletions

View File

@ -7,8 +7,8 @@ android {
applicationId "fr.gouv.etalab.mastodon"
minSdkVersion 15
targetSdkVersion 27
versionCode 105
versionName "1.7.5"
versionCode 106
versionName "1.7.6"
}
flavorDimensions "default"
buildTypes {
@ -44,7 +44,7 @@ dependencies {
implementation 'com.evernote:android-job:1.2.2'
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
implementation 'com.github.stom79:country-picker-android:1.2.0'
implementation 'com.github.stom79:mytransl:1.2'
implementation 'com.github.stom79:mytransl:1.4'
playstoreImplementation 'io.github.kobakei:ratethisapp:1.2.0'
implementation 'org.conscrypt:conscrypt-android:1.0.0.RC13'
implementation 'com.google.code.gson:gson:2.8.2'

View File

@ -25,7 +25,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<application
android:name=".activities.MainApplication"
android:allowBackup="true"
@ -178,9 +178,22 @@
<activity android:name=".activities.InstanceHealthActivity"
android:theme="@style/Base.V7.Theme.AppCompat.Dialog"
android:excludeFromRecents="true"/>
<activity android:name=".activities.ProxyActivity"
android:theme="@style/Base.V7.Theme.AppCompat.Dialog"
android:excludeFromRecents="true"/>
<activity android:name=".activities.ManageAccountsInListActivity"
android:windowSoftInputMode="adjustPan"
android:theme="@style/Base.V7.Theme.AppCompat.Dialog"
android:excludeFromRecents="true"/>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="fr.gouv.etalab.mastodon.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
</application>
</manifest>

View File

@ -740,6 +740,10 @@ public abstract class BaseMainActivity extends BaseActivity
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
return true;
case R.id.action_proxy:
intent = new Intent(getApplicationContext(), ProxyActivity.class);
startActivity(intent);
return true;
case R.id.action_export:
if(Build.VERSION.SDK_INT >= 23 ){
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) {
@ -821,7 +825,7 @@ public abstract class BaseMainActivity extends BaseActivity
final SwitchCompat set_push_hometimeline = dialogView.findViewById(R.id.set_push_hometimeline);
final SwitchCompat set_push_notification = dialogView.findViewById(R.id.set_push_notification);
boolean notif_hometimeline = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, true);
boolean notif_hometimeline = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, false);
boolean notif_follow = sharedpreferences.getBoolean(Helper.SET_NOTIF_FOLLOW, true);
boolean notif_add = sharedpreferences.getBoolean(Helper.SET_NOTIF_ADD, true);
boolean notif_ask = sharedpreferences.getBoolean(Helper.SET_NOTIF_ASK, true);
@ -1096,7 +1100,7 @@ public abstract class BaseMainActivity extends BaseActivity
if(matchStart < matchEnd && sharedText.length() >= matchEnd)
sharedText = sharedText.substring(matchStart, matchEnd);
}
new RetrieveMetaDataAsyncTask(sharedText, BaseMainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new RetrieveMetaDataAsyncTask(BaseMainActivity.this, sharedText, BaseMainActivity.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Intent intentToot = new Intent(getApplicationContext(), TootActivity.class);
Bundle b = new Bundle();
b.putString("sharedSubject", sharedSubject);

View File

@ -140,7 +140,7 @@ public class InstanceHealthActivity extends BaseActivity {
try {
HashMap<String, String> parameters = new HashMap<>();
parameters.put("name", instance.trim());
final String response = new HttpsConnection().get("https://instances.social/api/1.0/instances/show", 30, parameters, Helper.THEKINRAR_SECRET_TOKEN );
final String response = new HttpsConnection(InstanceHealthActivity.this).get("https://instances.social/api/1.0/instances/show", 30, parameters, Helper.THEKINRAR_SECRET_TOKEN );
if( response != null)
instanceSocial = API.parseInstanceSocialResponse(getApplicationContext(), new JSONObject(response));
runOnUiThread(new Runnable() {

View File

@ -125,7 +125,7 @@ public class LoginActivity extends BaseActivity {
@Override
public void run() {
try {
final String response = new HttpsConnection().get("https://instances.social/api/1.0" + action, 30, parameters, Helper.THEKINRAR_SECRET_TOKEN );
final String response = new HttpsConnection(LoginActivity.this).get("https://instances.social/api/1.0" + action, 30, parameters, Helper.THEKINRAR_SECRET_TOKEN );
runOnUiThread(new Runnable() {
public void run() {
isLoadingInstance = false;
@ -252,7 +252,7 @@ public class LoginActivity extends BaseActivity {
@Override
public void run() {
try {
final String response = new HttpsConnection().post("https://" + instance + action, 30, parameters, null );
final String response = new HttpsConnection(LoginActivity.this).post("https://" + instance + action, 30, parameters, null );
runOnUiThread(new Runnable() {
public void run() {
JSONObject resobj;
@ -326,7 +326,7 @@ public class LoginActivity extends BaseActivity {
@Override
public void run() {
try {
final String response = new HttpsConnection().post("https://" + instance + "/oauth/token", 30, parameters, null );
final String response = new HttpsConnection(LoginActivity.this).post("https://" + instance + "/oauth/token", 30, parameters, null );
runOnUiThread(new Runnable() {
public void run() {
JSONObject resobj;
@ -390,6 +390,9 @@ public class LoginActivity extends BaseActivity {
}else if(id == R.id.action_privacy){
Intent intent = new Intent(getApplicationContext(), PrivacyActivity.class);
startActivity(intent);
}else if(id == R.id.action_proxy){
Intent intent = new Intent(getApplicationContext(), ProxyActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}

View File

@ -0,0 +1,159 @@
/* Copyright 2017 Thomas Schneider
*
* This file is a part of Mastalab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Mastalab; if not,
* see <http://www.gnu.org/licenses>. */
package fr.gouv.etalab.mastodon.activities;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Spinner;
import java.lang.reflect.Proxy;
import fr.gouv.etalab.mastodon.R;
import fr.gouv.etalab.mastodon.helper.Helper;
import static fr.gouv.etalab.mastodon.helper.Helper.CHANGE_THEME_INTENT;
import static fr.gouv.etalab.mastodon.helper.Helper.INTENT_ACTION;
/**
* Created by Thomas on 19/01/2018.
* Proxy activity class
*/
public class ProxyActivity extends BaseActivity {
private int count2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setTheme(R.style.AppThemeDark_NoActionBar);
setContentView(R.layout.activity_proxy);
getWindow().setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Bundle b = getIntent().getExtras();
if( getSupportActionBar() != null)
getSupportActionBar().hide();
final SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
//Enable proxy
boolean enable_proxy = sharedpreferences.getBoolean(Helper.SET_PROXY_ENABLED, false);
final CheckBox set_enable_proxy = findViewById(R.id.enable_proxy);
set_enable_proxy.setChecked(enable_proxy);
set_enable_proxy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(Helper.SET_PROXY_ENABLED, set_enable_proxy.isChecked());
editor.apply();
}
});
Button save = findViewById(R.id.set_proxy_save);
final EditText host = findViewById(R.id.host);
final EditText port = findViewById(R.id.port);
final EditText proxy_login = findViewById(R.id.proxy_login);
final EditText proxy_password = findViewById(R.id.proxy_password);
String hostVal = sharedpreferences.getString(Helper.SET_PROXY_HOST, "127.0.0.1");
int portVal = sharedpreferences.getInt(Helper.SET_PROXY_PORT, 8118);
final String login = sharedpreferences.getString(Helper.SET_PROXY_LOGIN, null);
final String pwd = sharedpreferences.getString(Helper.SET_PROXY_PASSWORD, null);
if( hostVal.length() > 0)
host.setText(hostVal);
port.setText(String.valueOf(portVal));
if( login != null && login.length() > 0)
proxy_login.setText(login);
if( pwd != null && proxy_password.length() > 0)
proxy_password.setText(pwd);
count2 = 0;
final Spinner proxy_type = findViewById(R.id.type);
ArrayAdapter<CharSequence> adapterTrans = ArrayAdapter.createFromResource(ProxyActivity.this,
R.array.proxy_type, android.R.layout.simple_spinner_item);
proxy_type.setAdapter(adapterTrans);
proxy_type.setSelection(sharedpreferences.getInt(Helper.SET_PROXY_TYPE, 0));
proxy_type.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if( count2 > 0){
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putInt(Helper.SET_PROXY_TYPE, position);
editor.apply();
}else {
count2++;
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String hostVal = host.getText().toString().trim();
String portVal = port.getText().toString().trim();
String proxy_loginVal = proxy_login.getText().toString().trim();
String proxy_passwordVal = proxy_password.getText().toString().trim();
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.SET_PROXY_HOST, hostVal);
editor.putInt(Helper.SET_PROXY_PORT, Integer.parseInt(portVal));
editor.putString(Helper.SET_PROXY_LOGIN, proxy_loginVal);
editor.putString(Helper.SET_PROXY_PASSWORD, proxy_passwordVal);
editor.apply();
finish();
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -184,7 +184,7 @@ public class RemoteFollowActivity extends BaseActivity implements OnRetrieveRemo
@Override
public void run() {
try {
final String response = new HttpsConnection().get("https://instances.social/api/1.0" + action, 30, parameters, Helper.THEKINRAR_SECRET_TOKEN );
final String response = new HttpsConnection(RemoteFollowActivity.this).get("https://instances.social/api/1.0" + action, 30, parameters, Helper.THEKINRAR_SECRET_TOKEN );
runOnUiThread(new Runnable() {
public void run() {
isLoadingInstance = false;

View File

@ -21,11 +21,14 @@ import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.net.Uri;
import android.support.v4.content.FileProvider;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog;
import android.content.ActivityNotFoundException;
@ -84,8 +87,12 @@ import com.github.stom79.mytransl.translate.Translate;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
@ -148,6 +155,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
private String visibility;
private final int PICK_IMAGE = 56556;
private final int TAKE_PHOTO = 56532;
private ImageButton toot_picture;
private LinearLayout toot_picture_container;
private ArrayList<Attachment> attachments;
@ -346,7 +354,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
.load(url)
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
BitmapDrawable ppDrawable = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(25, getApplicationContext()), (int) Helper.convertDpToPixel(25, getApplicationContext()), true));
if( pp_actionBar != null){
pp_actionBar.setImageDrawable(ppDrawable);
@ -681,6 +689,46 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
}
}
String mCurrentPhotoPath;
File photoFile = null;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
try {
photoFile = createImageFile();
} catch (IOException ignored) {Toast.makeText(getApplicationContext(),R.string.toot_select_image_error,Toast.LENGTH_LONG).show();}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"fr.gouv.etalab.mastodon.fileProvider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, TAKE_PHOTO);
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
@ -707,6 +755,55 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
toot_content.setText(result.get(0));
toot_content.setSelection(toot_content.getText().length());
}
}else if (requestCode == TAKE_PHOTO && resultCode == RESULT_OK) {
new asyncPicture(TootActivity.this, photoFile).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
private static class asyncPicture extends AsyncTask<Void, Void, Void> {
ByteArrayInputStream bs;
WeakReference<Activity> activityWeakReference;
WeakReference<File> fileWeakReference;
asyncPicture(Activity activity, File photoFile){
this.activityWeakReference = new WeakReference<>(activity);
this.fileWeakReference = new WeakReference<>(photoFile);
}
@Override
protected Void doInBackground(Void... voids) {
Bitmap takenImage = BitmapFactory.decodeFile(String.valueOf(this.fileWeakReference.get()));
int size = takenImage.getByteCount();
//Resize image to 2 meg
double resize = ((double)size)/((double)16777216);
Bitmap newBitmap;
if( resize > 1 ){
newBitmap = Bitmap.createScaledBitmap(takenImage, (int)(takenImage.getWidth()/resize),
(int)(takenImage.getHeight()/resize), false);
}else {
newBitmap = takenImage;
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
newBitmap.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
bs = new ByteArrayInputStream(bitmapdata);
return null;
}
@Override
protected void onPostExecute(Void result) {
ImageButton toot_picture;
LinearLayout toot_picture_container;
toot_picture = this.activityWeakReference.get().findViewById(R.id.toot_picture);
toot_picture_container = this.activityWeakReference.get().findViewById(R.id.toot_picture_container);
toot_picture_container.setVisibility(View.VISIBLE);
toot_picture.setEnabled(false);
new HttpsConnection(this.activityWeakReference.get()).upload(bs, (TootActivity)this.activityWeakReference.get());
}
}
@ -930,6 +1027,9 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
alertDialogEmoji = builder.show();
return true;
case R.id.action_photo_camera:
dispatchTakePictureIntent();
return true;
case R.id.action_microphone:
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
@ -1194,7 +1294,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
.load(url)
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
imageView.setImageBitmap(resource);
}
});
@ -1293,7 +1393,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
.into(new SimpleTarget<Bitmap>() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
media_picture.setImageBitmap(resource);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
media_picture.setImageAlpha(60);
@ -1692,7 +1792,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount
.load(url)
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
imageView.setImageBitmap(resource);
}
});

View File

@ -119,7 +119,7 @@ public class WebviewConnectActivity extends BaseActivity {
@Override
public void run() {
try {
final String response = new HttpsConnection().post("https://" + instance + action, 30, parameters, null);
final String response = new HttpsConnection(WebviewConnectActivity.this).post("https://" + instance + action, 30, parameters, null);
JSONObject resobj;
try {
resobj = new JSONObject(response);

View File

@ -14,16 +14,17 @@
* see <http://www.gnu.org/licenses>. */
package fr.gouv.etalab.mastodon.asynctasks;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Patterns;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import fr.gouv.etalab.mastodon.client.HttpsConnection;
import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMetaDataInterface;
@ -40,10 +41,12 @@ public class RetrieveMetaDataAsyncTask extends AsyncTask<Void, Void, Void> {
private String url;
private boolean error = false;
private String image, title, description;
private WeakReference<Context> contextWeakReference;
public RetrieveMetaDataAsyncTask(String url, OnRetrieveMetaDataInterface onRetrieveRemoteAccountInterface){
public RetrieveMetaDataAsyncTask(Context context, String url, OnRetrieveMetaDataInterface onRetrieveRemoteAccountInterface){
this.url = url;
this.listener = onRetrieveRemoteAccountInterface;
this.contextWeakReference = new WeakReference<>(context);
}
@Override
@ -70,7 +73,7 @@ public class RetrieveMetaDataAsyncTask extends AsyncTask<Void, Void, Void> {
Pattern descriptionPattern = Pattern.compile("meta\\s+property=[\"']og:description[\"']\\s+content=[\"'](.*)[\"']");
Pattern imagePattern = Pattern.compile("meta\\s+property=[\"']og:image[\"']\\s+content=[\"'](.*)[\"']");
try {
String response = new HttpsConnection().get(potentialUrl);
String response = new HttpsConnection(this.contextWeakReference.get()).get(potentialUrl);
Matcher matcherTitle = titlePattern.matcher(response);
Matcher matcherDescription = descriptionPattern.matcher(response);
Matcher matcherImage = imagePattern.matcher(response);

View File

@ -123,7 +123,7 @@ public class API {
*/
public APIResponse getInstance() {
try {
String response = new HttpsConnection().get(getAbsoluteUrl("/instance"), 30, null, prefKeyOauthTokenT);
String response = new HttpsConnection(context).get(getAbsoluteUrl("/instance"), 30, null, prefKeyOauthTokenT);
Instance instanceEntity = parseInstance(new JSONObject(response));
apiResponse.setInstance(instanceEntity);
} catch (HttpsConnection.HttpsConnectionException e) {
@ -166,7 +166,7 @@ public class API {
requestParams.put("header",header);
}
try {
new HttpsConnection().patch(getAbsoluteUrl("/accounts/update_credentials"), 60, requestParams, prefKeyOauthTokenT);
new HttpsConnection(context).patch(getAbsoluteUrl("/accounts/update_credentials"), 60, requestParams, prefKeyOauthTokenT);
} catch (HttpsConnection.HttpsConnectionException e) {
e.printStackTrace();
setError(e.getStatusCode(), e);
@ -185,7 +185,7 @@ public class API {
public Account verifyCredentials() {
account = new Account();
try {
String response = new HttpsConnection().get(getAbsoluteUrl("/accounts/verify_credentials"), 60, null, prefKeyOauthTokenT);
String response = new HttpsConnection(context).get(getAbsoluteUrl("/accounts/verify_credentials"), 60, null, prefKeyOauthTokenT);
account = parseAccountResponse(context, new JSONObject(response));
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
@ -204,7 +204,7 @@ public class API {
account = new Account();
try {
String response = new HttpsConnection().get(getAbsoluteUrl(String.format("/accounts/%s",accountId)), 60, null, prefKeyOauthTokenT);
String response = new HttpsConnection(context).get(getAbsoluteUrl(String.format("/accounts/%s",accountId)), 60, null, prefKeyOauthTokenT);
account = parseAccountResponse(context, new JSONObject(response));
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
@ -227,7 +227,7 @@ public class API {
HashMap<String, String> params = new HashMap<>();
params.put("id",accountId);
try {
String response = new HttpsConnection().get(getAbsoluteUrl("/accounts/relationships"), 60, params, prefKeyOauthTokenT);
String response = new HttpsConnection(context).get(getAbsoluteUrl("/accounts/relationships"), 60, params, prefKeyOauthTokenT);
relationships = parseRelationshipResponse(new JSONArray(response));
if( relationships != null && relationships.size() > 0)
relationship = relationships.get(0);
@ -259,7 +259,7 @@ public class API {
}
List<Relationship> relationships = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl("/accounts/relationships"), 60, params, prefKeyOauthTokenT);
relationships = parseRelationshipResponse(new JSONArray(response));
apiResponse.setSince_id(httpsConnection.getSince_id());
@ -348,7 +348,7 @@ public class API {
statuses = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl(String.format("/accounts/%s/statuses", accountId)), 60, params, prefKeyOauthTokenT);
statuses = parseStatuses(new JSONArray(response));
apiResponse.setSince_id(httpsConnection.getSince_id());
@ -375,7 +375,7 @@ public class API {
statuses = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl(String.format("/statuses/%s", statusId)), 60, null, prefKeyOauthTokenT);
Status status = parseStatuses(context, new JSONObject(response));
statuses.add(status);
@ -397,7 +397,7 @@ public class API {
public fr.gouv.etalab.mastodon.client.Entities.Context getStatusContext(String statusId) {
fr.gouv.etalab.mastodon.client.Entities.Context statusContext = new fr.gouv.etalab.mastodon.client.Entities.Context();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl(String.format("/statuses/%s/context", statusId)), 60, null, prefKeyOauthTokenT);
statusContext = parseContext(new JSONObject(response));
} catch (HttpsConnection.HttpsConnectionException e) {
@ -448,7 +448,7 @@ public class API {
params.put("limit",String.valueOf(limit));
statuses = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl("/timelines/home"), 60, params, prefKeyOauthTokenT);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
@ -507,7 +507,7 @@ public class API {
params.put("limit",String.valueOf(limit));
statuses = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl("/timelines/public"), 60, params, prefKeyOauthTokenT);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
@ -556,7 +556,7 @@ public class API {
params.put("limit",String.valueOf(limit));
statuses = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl(String.format("/timelines/tag/%s",tag.trim())), 60, params, prefKeyOauthTokenT);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
@ -630,7 +630,7 @@ public class API {
params.put("limit",String.valueOf(limit));
accounts = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl(action), 60, params, prefKeyOauthTokenT);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
@ -673,7 +673,7 @@ public class API {
params.put("limit",String.valueOf(limit));
accounts = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl("/follow_requests"), 60, params, prefKeyOauthTokenT);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
@ -716,7 +716,7 @@ public class API {
params.put("limit",String.valueOf(limit));
statuses = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl("/favourites"), 60, params, prefKeyOauthTokenT);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
@ -752,7 +752,7 @@ public class API {
HashMap<String, String> params = new HashMap<>();
params.put("notifications", Boolean.toString(muteNotifications));
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
httpsConnection.post(getAbsoluteUrl(String.format("/accounts/%s/mute", targetedId)), 60, params, prefKeyOauthTokenT);
actionCode = httpsConnection.getActionCode();
} catch (HttpsConnection.HttpsConnectionException e) {
@ -882,7 +882,7 @@ public class API {
if(statusAction != StatusAction.UNSTATUS ) {
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
httpsConnection.post(getAbsoluteUrl(action), 60, params, prefKeyOauthTokenT);
actionCode = httpsConnection.getActionCode();
} catch (HttpsConnection.HttpsConnectionException e) {
@ -892,7 +892,7 @@ public class API {
}
}else{
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
httpsConnection.delete(getAbsoluteUrl(action), 60, null, prefKeyOauthTokenT);
actionCode = httpsConnection.getActionCode();
} catch (HttpsConnection.HttpsConnectionException e) {
@ -939,7 +939,7 @@ public class API {
statuses = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.post(getAbsoluteUrl("/statuses"), 60, params, prefKeyOauthTokenT);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
@ -971,7 +971,7 @@ public class API {
action = "/notifications/dismiss";
}
try {
new HttpsConnection().post(getAbsoluteUrl(action), 60, params, prefKeyOauthTokenT);
new HttpsConnection(context).post(getAbsoluteUrl(action), 60, params, prefKeyOauthTokenT);
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
@ -1060,7 +1060,7 @@ public class API {
List<Notification> notifications = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl("/notifications"), 60, params, prefKeyOauthTokenT);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
@ -1092,7 +1092,7 @@ public class API {
params.put("description", description);
}
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.put(getAbsoluteUrl(String.format("/media/%s", mediaId)), 240, params, prefKeyOauthTokenT);
attachment = parseAttachmentResponse(new JSONObject(response));
} catch (HttpsConnection.HttpsConnectionException e) {
@ -1114,7 +1114,7 @@ public class API {
HashMap<String, String> params = new HashMap<>();
params.put("q", query);
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl("/search"), 60, params, prefKeyOauthTokenT);
results = parseResultsResponse(new JSONObject(response));
} catch (HttpsConnection.HttpsConnectionException e) {
@ -1158,7 +1158,7 @@ public class API {
params.put("limit", String.valueOf(count));
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl("/accounts/search"), 60, params, prefKeyOauthTokenT);
accounts = parseAccountResponse(new JSONArray(response));
apiResponse.setSince_id(httpsConnection.getSince_id());
@ -1184,7 +1184,7 @@ public class API {
public APIResponse getCustomEmoji() {
List<Emojis> emojis = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl("/custom_emojis"), 60, null, prefKeyOauthTokenT);
emojis = parseEmojis(new JSONArray(response));
apiResponse.setSince_id(httpsConnection.getSince_id());
@ -1209,7 +1209,7 @@ public class API {
List<fr.gouv.etalab.mastodon.client.Entities.List> lists = new ArrayList<>();
try {
String response = new HttpsConnection().get(getAbsoluteUrl("/lists"), 60, null, prefKeyOauthTokenT);
String response = new HttpsConnection(context).get(getAbsoluteUrl("/lists"), 60, null, prefKeyOauthTokenT);
lists = parseLists(new JSONArray(response));
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
@ -1229,7 +1229,7 @@ public class API {
List<fr.gouv.etalab.mastodon.client.Entities.List> lists = new ArrayList<>();
fr.gouv.etalab.mastodon.client.Entities.List list;
try {
String response = new HttpsConnection().get(getAbsoluteUrl(String.format("/accounts/%s/lists", userId)), 60, null, prefKeyOauthTokenT);
String response = new HttpsConnection(context).get(getAbsoluteUrl(String.format("/accounts/%s/lists", userId)), 60, null, prefKeyOauthTokenT);
list = parseList(new JSONObject(response));
lists.add(list);
} catch (HttpsConnection.HttpsConnectionException e) {
@ -1261,7 +1261,7 @@ public class API {
params.put("limit",String.valueOf(limit));
statuses = new ArrayList<>();
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl(String.format("/timelines/list/%s",list_id)), 60, params, prefKeyOauthTokenT);
apiResponse.setSince_id(httpsConnection.getSince_id());
apiResponse.setMax_id(httpsConnection.getMax_id());
@ -1295,7 +1295,7 @@ public class API {
limit = 50;
params.put("limit",String.valueOf(limit));
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
String response = httpsConnection.get(getAbsoluteUrl(String.format("/lists/%s/accounts", listId)), 60, params, prefKeyOauthTokenT);
accounts = parseAccountResponse(new JSONArray(response));
apiResponse.setSince_id(httpsConnection.getSince_id());
@ -1321,7 +1321,7 @@ public class API {
List<fr.gouv.etalab.mastodon.client.Entities.List> lists = new ArrayList<>();
fr.gouv.etalab.mastodon.client.Entities.List list;
try {
String response = new HttpsConnection().get(getAbsoluteUrl(String.format("/lists/%s",id)), 60, null, prefKeyOauthTokenT);
String response = new HttpsConnection(context).get(getAbsoluteUrl(String.format("/lists/%s",id)), 60, null, prefKeyOauthTokenT);
list = parseList(new JSONObject(response));
lists.add(list);
} catch (HttpsConnection.HttpsConnectionException e) {
@ -1355,7 +1355,7 @@ public class API {
List<fr.gouv.etalab.mastodon.client.Entities.List> lists = new ArrayList<>();
fr.gouv.etalab.mastodon.client.Entities.List list;
try {
new HttpsConnection().post(getAbsoluteUrl(String.format("/lists/%s/accounts", id)), 60, params, prefKeyOauthTokenT);
new HttpsConnection(context).post(getAbsoluteUrl(String.format("/lists/%s/accounts", id)), 60, params, prefKeyOauthTokenT);
} catch (HttpsConnection.HttpsConnectionException e) {
setError(e.getStatusCode(), e);
}catch (Exception e) {
@ -1372,7 +1372,7 @@ public class API {
*/
public int deleteAccountFromList(String id, String[] account_ids){
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
StringBuilder parameters = new StringBuilder();
HashMap<String, String> params = new HashMap<>();
for(String val: account_ids)
@ -1405,7 +1405,7 @@ public class API {
List<fr.gouv.etalab.mastodon.client.Entities.List> lists = new ArrayList<>();
fr.gouv.etalab.mastodon.client.Entities.List list;
try {
String response = new HttpsConnection().post(getAbsoluteUrl("/lists"), 60, params, prefKeyOauthTokenT);
String response = new HttpsConnection(context).post(getAbsoluteUrl("/lists"), 60, params, prefKeyOauthTokenT);
list = parseList(new JSONObject(response));
lists.add(list);
} catch (HttpsConnection.HttpsConnectionException e) {
@ -1427,7 +1427,7 @@ public class API {
Card card = null;
try {
String response = new HttpsConnection().get(getAbsoluteUrl(String.format("/statuses/%s/card", statusId)), 60, null, prefKeyOauthTokenT);
String response = new HttpsConnection(context).get(getAbsoluteUrl(String.format("/statuses/%s/card", statusId)), 60, null, prefKeyOauthTokenT);
card = parseCardResponse(new JSONObject(response));
}catch (Exception ignored) {ignored.printStackTrace();}
return card;
@ -1446,7 +1446,7 @@ public class API {
List<fr.gouv.etalab.mastodon.client.Entities.List> lists = new ArrayList<>();
fr.gouv.etalab.mastodon.client.Entities.List list;
try {
String response = new HttpsConnection().put(getAbsoluteUrl(String.format("/lists/%s", id)), 60, params, prefKeyOauthTokenT);
String response = new HttpsConnection(context).put(getAbsoluteUrl(String.format("/lists/%s", id)), 60, params, prefKeyOauthTokenT);
list = parseList(new JSONObject(response));
lists.add(list);
} catch (HttpsConnection.HttpsConnectionException e) {
@ -1466,7 +1466,7 @@ public class API {
*/
public int deleteList(String id){
try {
HttpsConnection httpsConnection = new HttpsConnection();
HttpsConnection httpsConnection = new HttpsConnection(context);
httpsConnection.delete(getAbsoluteUrl(String.format("/lists/%s", id)), 60, null, prefKeyOauthTokenT);
actionCode = httpsConnection.getActionCode();
} catch (HttpsConnection.HttpsConnectionException e) {

View File

@ -1,5 +1,6 @@
package fr.gouv.etalab.mastodon.client.Glide;
import android.content.Context;
import android.support.annotation.NonNull;
import com.bumptech.glide.Priority;
@ -8,6 +9,7 @@ import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import fr.gouv.etalab.mastodon.client.HttpsConnection;
@ -19,14 +21,16 @@ import fr.gouv.etalab.mastodon.client.HttpsConnection;
public class CustomStreamFetcher implements DataFetcher<InputStream> {
private GlideUrl url;
private WeakReference<Context> contextWeakReference;
CustomStreamFetcher(GlideUrl url) {
CustomStreamFetcher(Context context, GlideUrl url) {
this.contextWeakReference = new WeakReference<>(context);
this.url = url;
}
@Override
public void loadData(Priority priority, DataCallback<? super InputStream> callback) {
callback.onDataReady(new HttpsConnection().getPicture(url.toStringUrl()));
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
callback.onDataReady(new HttpsConnection(this.contextWeakReference.get()).getPicture(url.toStringUrl()));
}
@Override

View File

@ -1,5 +1,7 @@
package fr.gouv.etalab.mastodon.client.Glide;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.bumptech.glide.load.Options;
@ -9,6 +11,8 @@ import com.bumptech.glide.load.model.ModelLoaderFactory;
import com.bumptech.glide.load.model.MultiModelLoaderFactory;
import java.io.InputStream;
import java.lang.ref.WeakReference;
/**
@ -18,26 +22,32 @@ import java.io.InputStream;
public class HttpsUrlLoader implements ModelLoader<GlideUrl, InputStream> {
private static WeakReference<Context> contextWeakReference;
HttpsUrlLoader() {}
HttpsUrlLoader(Context context) {
contextWeakReference = new WeakReference<>(context);}
@Nullable
@Override
public LoadData<InputStream> buildLoadData(GlideUrl glideUrl, int width, int height, Options options) {
return new LoadData<>(glideUrl, new CustomStreamFetcher(glideUrl));
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl glideUrl, int width, int height, @NonNull Options options) {
return new LoadData<>(glideUrl, new CustomStreamFetcher(contextWeakReference.get(), glideUrl));
}
@Override
public boolean handles(GlideUrl glideUrl) {
public boolean handles(@NonNull GlideUrl glideUrl) {
return true;
}
public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
Factory(Context context){
contextWeakReference = new WeakReference<>(context);
}
@NonNull
@Override
public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
return new HttpsUrlLoader();
public ModelLoader<GlideUrl, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
return new HttpsUrlLoader(contextWeakReference.get());
}
@Override
public void teardown() {

View File

@ -1,6 +1,7 @@
package fr.gouv.etalab.mastodon.client.Glide;
import android.content.Context;
import android.support.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
@ -20,8 +21,8 @@ import java.io.InputStream;
public final class TLSLibraryGlideModule extends AppGlideModule {
@Override
public void registerComponents(Context context, Glide glide, Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new HttpsUrlLoader.Factory());
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new HttpsUrlLoader.Factory(context));
}
@Override

View File

@ -31,7 +31,11 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
@ -66,11 +70,36 @@ public class HttpsConnection {
private String since_id, max_id;
private Context context;
private int CHUNK_SIZE = 4096;
private SharedPreferences sharedpreferences;
private Proxy proxy;
public HttpsConnection(){}
public HttpsConnection(Context context){
this.context = context;
sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
boolean proxyEnabled = sharedpreferences.getBoolean(Helper.SET_PROXY_ENABLED, false);
int type = sharedpreferences.getInt(Helper.SET_PROXY_TYPE, 0);
proxy = null;
if( proxyEnabled ){
String host = sharedpreferences.getString(Helper.SET_PROXY_HOST, "127.0.0.1");
int port = sharedpreferences.getInt(Helper.SET_PROXY_PORT, 8118);
if( type == 0 )
proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
else
proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(host, port));
final String login = sharedpreferences.getString(Helper.SET_PROXY_LOGIN, null);
final String pwd = sharedpreferences.getString(Helper.SET_PROXY_PASSWORD, null);
if( login != null) {
Authenticator authenticator = new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
assert pwd != null;
return (new PasswordAuthentication(login,
pwd.toCharArray()));
}
};
Authenticator.setDefault(authenticator);
}
}
}
@ -95,7 +124,10 @@ public class HttpsConnection {
postData.append(String.valueOf(param.getValue()));
}
URL url = new URL(urlConnection + "?" + postData);
httpsURLConnection = (HttpsURLConnection)url.openConnection();
if( proxy !=null )
httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy);
else
httpsURLConnection = (HttpsURLConnection)url.openConnection();
httpsURLConnection.setConnectTimeout(timeout * 1000);
httpsURLConnection.setRequestProperty("http.keepAlive", "false");
httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT);
@ -124,7 +156,10 @@ public class HttpsConnection {
HttpURLConnection httpURLConnection;
if( urlConnection.startsWith("https://")) {
URL url = new URL(urlConnection);
httpsURLConnection = (HttpsURLConnection) url.openConnection();
if( proxy !=null )
httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy);
else
httpsURLConnection = (HttpsURLConnection)url.openConnection();
httpsURLConnection.setConnectTimeout(30 * 1000);
httpsURLConnection.setRequestProperty("http.keepAlive", "false");
httpsURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36");
@ -145,7 +180,10 @@ public class HttpsConnection {
return response;
}else{
URL url = new URL(urlConnection);
httpURLConnection = (HttpURLConnection) url.openConnection();
if( proxy !=null )
httpURLConnection = (HttpURLConnection)url.openConnection(proxy);
else
httpURLConnection = (HttpURLConnection)url.openConnection();
httpURLConnection.setConnectTimeout(30 * 1000);
httpURLConnection.setRequestProperty("http.keepAlive", "false");
httpURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36");
@ -188,7 +226,10 @@ public class HttpsConnection {
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
httpsURLConnection = (HttpsURLConnection)url.openConnection();
if( proxy !=null )
httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy);
else
httpsURLConnection = (HttpsURLConnection)url.openConnection();
httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT);
httpsURLConnection.setConnectTimeout(timeout * 1000);
httpsURLConnection.setDoOutput(true);
@ -231,7 +272,10 @@ public class HttpsConnection {
if (downloadUrl.startsWith("https://")) {
try {
url = new URL(downloadUrl);
httpsURLConnection = (HttpsURLConnection) url.openConnection();
if( proxy !=null )
httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy);
else
httpsURLConnection = (HttpsURLConnection)url.openConnection();
httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT);
int responseCode = httpsURLConnection.getResponseCode();
@ -318,7 +362,10 @@ public class HttpsConnection {
} else {
try {
url = new URL(downloadUrl);
httpURLConnection = (HttpURLConnection) url.openConnection();
if( proxy !=null )
httpURLConnection = (HttpURLConnection)url.openConnection(proxy);
else
httpURLConnection = (HttpURLConnection)url.openConnection();
httpURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT);
int responseCode = httpURLConnection.getResponseCode();
@ -412,7 +459,10 @@ public class HttpsConnection {
public InputStream getPicture(final String downloadUrl) {
try {
URL url = new URL(downloadUrl);
httpsURLConnection = (HttpsURLConnection) url.openConnection();
if( proxy !=null )
httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy);
else
httpsURLConnection = (HttpsURLConnection)url.openConnection();
httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory());
httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT);
int responseCode = httpsURLConnection.getResponseCode();
@ -449,7 +499,6 @@ public class HttpsConnection {
String boundary = "*****" + Long.toString(System.currentTimeMillis()) + "*****";
String lineEnd = "\r\n";
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null);
final URL url = new URL("https://"+Helper.getLiveInstance(context)+"/api/v1/media");
ByteArrayOutputStream ous = null;
@ -475,7 +524,10 @@ public class HttpsConnection {
lengthSent += ("Content-Disposition: form-data; name=\"file\";filename=\"picture.png\"" + lineEnd).getBytes().length;
lengthSent += 2 * (lineEnd).getBytes().length;
httpsURLConnection = (HttpsURLConnection) url.openConnection();
if( proxy !=null )
httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy);
else
httpsURLConnection = (HttpsURLConnection)url.openConnection();
httpsURLConnection.setFixedLengthStreamingMode(lengthSent);
httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT);
@ -599,7 +651,10 @@ public class HttpsConnection {
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
httpsURLConnection = (HttpsURLConnection)url.openConnection();
if( proxy !=null )
httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy);
else
httpsURLConnection = (HttpsURLConnection)url.openConnection();
httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT);
httpsURLConnection.setConnectTimeout(timeout * 1000);
httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory());
@ -650,7 +705,10 @@ public class HttpsConnection {
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
httpsURLConnection = (HttpsURLConnection)url.openConnection();
if( proxy !=null )
httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy);
else
httpsURLConnection = (HttpsURLConnection)url.openConnection();
httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT);
httpsURLConnection.setConnectTimeout(timeout * 1000);
httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory());
@ -699,7 +757,10 @@ public class HttpsConnection {
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
httpsURLConnection = (HttpsURLConnection)url.openConnection();
if( proxy !=null )
httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy);
else
httpsURLConnection = (HttpsURLConnection)url.openConnection();
httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT);
httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory());
if( token != null)

View File

@ -89,7 +89,6 @@ import fr.gouv.etalab.mastodon.activities.MediaActivity;
import fr.gouv.etalab.mastodon.activities.ShowAccountActivity;
import fr.gouv.etalab.mastodon.activities.ShowConversationActivity;
import fr.gouv.etalab.mastodon.activities.TootActivity;
import fr.gouv.etalab.mastodon.activities.WebviewActivity;
import fr.gouv.etalab.mastodon.asynctasks.PostActionAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask;
import fr.gouv.etalab.mastodon.asynctasks.RetrieveRepliesAsyncTask;
@ -554,7 +553,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
//noinspection deprecation
statusToTranslate = Html.fromHtml(status.getReblog() != null ?status.getReblog().getContent():status.getContent()).toString();
//TODO: removes the replaceAll once fixed with the lib
myTransL.translate(statusToTranslate.replaceAll("%","%25"), myTransL.getLocale(), new Results() {
myTransL.translate(statusToTranslate, myTransL.getLocale(), new Results() {
@Override
public void onSuccess(Translate translate) {
if( translate.getTranslatedContent() != null) {
@ -985,12 +984,6 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
holder.status_cardview_video.setVisibility(View.GONE);
}
@Override
public boolean shouldOverrideUrlLoading (WebView view, String url){
Helper.openBrowser(context, url);
holder.status_cardview_webview.loadUrl(finalSrc);
return true;
}
});
holder.status_cardview_webview.loadUrl(finalSrc);
}

View File

@ -105,7 +105,7 @@ public class SettingsNotificationsFragment extends Fragment {
boolean notif_wifi = sharedpreferences.getBoolean(Helper.SET_WIFI_ONLY, false);
boolean notif_silent = sharedpreferences.getBoolean(Helper.SET_NOTIF_SILENT, false);
boolean notif_hometimeline = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, true);
boolean notif_hometimeline = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, false);
final String time_from = sharedpreferences.getString(Helper.SET_TIME_FROM, "07:00");
final String time_to = sharedpreferences.getString(Helper.SET_TIME_TO, "22:00");

View File

@ -269,6 +269,13 @@ public class Helper {
public static final String EP_AUTHORIZE = "/oauth/authorize";
//Proxy
public static final String SET_PROXY_ENABLED = "set_proxy_enabled";
public static final String SET_PROXY_TYPE = "set_proxy_type";
public static final String SET_PROXY_HOST = "set_proxy_host";
public static final String SET_PROXY_PORT = "set_proxy_port";
public static final String SET_PROXY_LOGIN = "set_proxy_login";
public static final String SET_PROXY_PASSWORD = "set_proxy_password";
//Refresh job
public static final int MINUTES_BETWEEN_NOTIFICATIONS_REFRESH = 15;
public static final int MINUTES_BETWEEN_HOME_TIMELINE = 30;

View File

@ -20,6 +20,8 @@ import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -101,7 +103,7 @@ public class HomeTimelineSyncJob extends Job {
if( !canNotify(getContext()))
return;
final SharedPreferences sharedpreferences = getContext().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
boolean notif_hometimeline = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, true);
boolean notif_hometimeline = sharedpreferences.getBoolean(Helper.SET_NOTIF_HOMETIMELINE, false);
//User disagree with home timeline refresh
if( !notif_hometimeline)
return; //Nothing is done
@ -151,7 +153,7 @@ public class HomeTimelineSyncJob extends Job {
//Also, if the toot comes from the owner, we will avoid to warn him/her...
if( max_id != null && (status.getId().equals(max_id)) || (account.getAcct() != null && status.getAccount().getAcct().trim().equals(account.getAcct().trim()) ))
continue;
String notificationUrl = status.getAccount().getAvatar();
final String notificationUrl = status.getAccount().getAvatar();
if(statuses.size() > 0 )
message = getContext().getResources().getQuantityString(R.plurals.other_notif_hometimeline, statuses.size(), statuses.size());
@ -173,35 +175,43 @@ public class HomeTimelineSyncJob extends Job {
else
title = getContext().getResources().getString(R.string.notif_pouet, status.getAccount().getUsername());
final String finalTitle = title;
Glide.with(getContext())
.asBitmap()
.load(notificationUrl)
.listener(new RequestListener<Bitmap>(){
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
Handler mainHandler = new Handler(Looper.getMainLooper());
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.mastodonlogo), finalTitle, finalMessage);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), statuses.get(0).getId());
editor.apply();
return false;
}
})
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
notify_user(getContext(), intent, notificationId, resource, finalTitle, finalMessage);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), statuses.get(0).getId());
editor.apply();
}
});
Runnable myRunnable = new Runnable() {
@Override
public void run() {Glide.with(getContext())
.asBitmap()
.load(notificationUrl)
.listener(new RequestListener<Bitmap>(){
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.mastodonlogo), finalTitle, finalMessage);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), statuses.get(0).getId());
editor.apply();
return false;
}
})
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
notify_user(getContext(), intent, notificationId, resource, finalTitle, finalMessage);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_HOMETIMELINE_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), statuses.get(0).getId());
editor.apply();
}
});
}
};
mainHandler.post(myRunnable);
}
}

View File

@ -20,6 +20,8 @@ import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -238,41 +240,51 @@ public class NotificationsSyncJob extends Job {
final String finalTitle = title;
Glide.with(getContext())
.asBitmap()
.load(notificationUrl)
.listener(new RequestListener<Bitmap>() {
Handler mainHandler = new Handler(Looper.getMainLooper());
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
final String finalNotificationUrl = notificationUrl;
Runnable myRunnable = new Runnable() {
@Override
public void run() {
Glide.with(getContext())
.asBitmap()
.load(finalNotificationUrl)
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.mastodonlogo), finalTitle, message);
String lastNotif = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), null);
if( lastNotif == null || Long.parseLong(notifications.get(0).getId()) > Long.parseLong(lastNotif)){
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), notifications.get(0).getId());
editor.apply();
}
return false;
}
})
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
notify_user(getContext(), intent, notificationId, resource, finalTitle, message);
String lastNotif = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), null);
if( lastNotif == null || Long.parseLong(notifications.get(0).getId()) > Long.parseLong(lastNotif)){
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), notifications.get(0).getId());
editor.apply();
}
}
});
}
};
mainHandler.post(myRunnable);
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
notify_user(getContext(), intent, notificationId, BitmapFactory.decodeResource(getContext().getResources(),
R.drawable.mastodonlogo), finalTitle, message);
String lastNotif = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), null);
if( lastNotif == null || Long.parseLong(notifications.get(0).getId()) > Long.parseLong(lastNotif)){
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), notifications.get(0).getId());
editor.apply();
}
return false;
}
})
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
notify_user(getContext(), intent, notificationId, resource, finalTitle, message);
String lastNotif = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), null);
if( lastNotif == null || Long.parseLong(notifications.get(0).getId()) > Long.parseLong(lastNotif)){
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + account.getId() + account.getInstance(), notifications.get(0).getId());
editor.apply();
}
}
});
}
}

View File

@ -21,10 +21,6 @@ import android.support.annotation.NonNull;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobRequest;
import org.conscrypt.Conscrypt;
import java.security.Provider;
import java.security.Security;
import java.util.Date;
import java.util.concurrent.TimeUnit;

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
</vector>

View File

@ -0,0 +1,70 @@
<?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:fitsSystemWindows="true"
tools:context="fr.gouv.etalab.mastodon.activities.ProxyActivity"
android:layout_margin="@dimen/fab_margin"
android:id="@+id/container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<CheckBox
android:id="@+id/enable_proxy"
android:checked="false"
android:text="@string/proxy_enable"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/type"
android:inputType="number"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/host"
android:inputType="textUri"
android:hint="@string/poxy_host"
android:layout_width="0dp"
android:layout_weight="3"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/port"
android:inputType="number"
android:hint="@string/poxy_port"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
</LinearLayout>
<EditText
android:id="@+id/proxy_login"
android:hint="@string/poxy_login"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/proxy_password"
android:inputType="textPassword"
android:hint="@string/poxy_password"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:layout_marginTop="5dp"
android:id="@+id/set_proxy_save"
android:layout_gravity="center"
android:gravity="center"
style="@style/Base.Widget.AppCompat.Button.Colored"
android:maxWidth="150dp"
android:text="@string/set_save_changes"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.FloatingActionButton
android:id="@+id/pickup_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_insert_photo"
android:visibility="invisible"
app:fabSize="mini" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/take_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_photo_camera"
android:visibility="invisible"
app:fabSize="mini" />
</FrameLayout>

View File

@ -25,6 +25,10 @@
android:id="@+id/action_export"
android:title="@string/data_export"
app:showAsAction="never" />
<item
android:id="@+id/action_proxy"
android:title="@string/proxy_set"
app:showAsAction="never" />
<item
android:id="@+id/action_logout"
android:title="@string/action_logout"

View File

@ -9,4 +9,8 @@
android:id="@+id/action_privacy"
android:title="@string/action_privacy"
app:showAsAction="never" />
<item
android:id="@+id/action_proxy"
android:title="@string/proxy_set"
app:showAsAction="never" />
</menu>

View File

@ -11,6 +11,11 @@
android:title="@string/insert_emoji"
android:icon="@drawable/ic_insert_emoticon"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_photo_camera"
android:title="@string/camera"
android:icon="@drawable/ic_photo_camera"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_microphone"
android:title="@string/microphone"

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">حدد صورة ...</string>
<string name="clear">نظيف</string>
<string name="microphone">الميكروفون</string>
<string name="camera">Camera</string>
<string name="speech_prompt">قل شيئا من فضلك</string>
<string name="speech_not_supported">معذرة ! إنّ جهازك لا يدعَم الإدخال الصوتي !</string>
<string name="delete_all">حذف الكل</string>
@ -440,4 +441,12 @@
<string name="data_export_toots">تصدير بيانات %1$s</string>
<string name="data_export_success">تم تصدير %1$s تبويقات من أصل %2$s.</string>
<string name="data_export_error">طرأ هناك خطأ أثناء تصدير بيانات %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -435,4 +436,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Wähle ein Bild…</string>
<string name="clear">Säubern</string>
<string name="microphone">Mikrofon</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Bitte sag etwas</string>
<string name="speech_not_supported">Sorry! Dein Gerät unterstützt keine Spracheingabe!</string>
<string name="delete_all">Alles löschen</string>
@ -421,4 +422,12 @@ Die Anwendung <b>nutzt keine Trackingwergzeuge</b>(Zielgruppenbestimmung, Fehler
<string name="data_export_toots">Status exportieren für %1$s</string>
<string name="data_export_success">%1$s Toots von %2$s wurden exportiert.</string>
<string name="data_export_error">Etwas ist schief gelaufen beim exportieren von%1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Επιλογή φωτογραφίας…</string>
<string name="clear">Καθαρισμός</string>
<string name="microphone">Μικρόφωνο</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Σε παρακαλώ πες κάτι</string>
<string name="speech_not_supported">Λυπάμαι, η συσκευή σου δεν υποστηρίζει φωνητική εισαγωγή!</string>
<string name="delete_all">Σβήσε τα όλα</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Seleccionar una imagen…</string>
<string name="clear">Borrar</string>
<string name="microphone">Micrófono</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Por favor, di algo</string>
<string name="speech_not_supported">¡Lo sentimos! ¡Tu dispositivo no es compatible con la entrada de voz!</string>
<string name="delete_all">Eliminar todo</string>
@ -427,4 +428,12 @@ Gracias a: </string>
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Hautatu irudi bat…</string>
<string name="clear">Garbitu</string>
<string name="microphone">Mikrofonoa</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Esan zerbait</string>
<string name="speech_not_supported">Zure gailuak ez du onartzen ahots sarrera!</string>
<string name="delete_all">Ezabatu guztiak</string>
@ -229,8 +230,8 @@
<string name="toast_unblock">Kontua ez dago jada blokeatuta!</string>
<string name="toast_mute">Kontua mututua izan da!</string>
<string name="toast_unmute">Kontua ez dago jada mututua!</string>
<string name="toast_follow">Kontua jarraitua izan da!</string>
<string name="toast_unfollow">Kontua ez dago jada jarraitua!</string>
<string name="toast_follow">Kontua jarraitzen hasi zara!</string>
<string name="toast_unfollow">Ez duzu jada kontu hau jarraitzen!</string>
<string name="toast_reblog">Toot-a bultzatu da!</string>
<string name="toast_unreblog">Toot-a ez dago jada bultzatua!</string>
<string name="toast_favourite">Toot-a zure gogokoetara gehitu da!</string>
@ -431,4 +432,12 @@ Eskerrik asko Stéphane logoagatik. </string>
<string name="data_export_toots">Esportatu %1$s(e)ren mezuak</string>
<string name="data_export_success">%1$s toot esportatu dira %2$stik.</string>
<string name="data_export_error">Zerbait ez da behar bezala joan %1$s(e)ko datuak esportatzean</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Changer l\'image…</string>
<string name="clear">Nettoyer</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Veuillez dire quelque chose</string>
<string name="speech_not_supported">Désolé ! Votre appareil ne supporte pas la commande vocale !</string>
<string name="delete_all">Tout effacer</string>
@ -430,4 +431,12 @@
<string name="data_export_toots">Pouets exportés pour %1$s</string>
<string name="data_export_success">%1$s pouets sur %2$s ont été exportés.</string>
<string name="data_export_error">Une erreur est survenue lors de l\'exportation des pouets pour %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -438,4 +439,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Memilih gambar…</string>
<string name="clear">Bersih</string>
<string name="microphone">Mikropon</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Tolong katakan sesuatu</string>
<string name="speech_not_supported">Maaf! Perangkat Anda tidak mendukung input suara!</string>
<string name="delete_all">Hapus semua</string>
@ -431,4 +432,12 @@ https://yandex.ru/legal/confidential/?lang=en
<string name="data_export_toots">Status ekspor untuk %1$s</string>
<string name="data_export_success">%1$s panjang dari %2$s telah diekspor.</string>
<string name="data_export_error">Terdapat kesalahan saat mengekspor data untuk %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">画像を選択…</string>
<string name="clear">削除</string>
<string name="microphone">マイク</string>
<string name="camera">Camera</string>
<string name="speech_prompt">何か話してみてください</string>
<string name="speech_not_supported">お使いのデバイスは音声入力をサポートしておりません!</string>
<string name="delete_all">すべて削除</string>
@ -421,4 +422,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -429,4 +430,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Kies een afbeelding…</string>
<string name="clear">Leegmaken</string>
<string name="microphone">Microfoon</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Zeg naar iets</string>
<string name="speech_not_supported">Sorry! Jouw apparaat ondersteund geen geluidsinvoer!</string>
<string name="delete_all">Alles verwijderen</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Velg et bilde…</string>
<string name="clear">Ren</string>
<string name="microphone">Mikrofon</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Si noe, vær så snill</string>
<string name="speech_not_supported">Beklager! Enheten støtter ikke taleinngangen!</string>
<string name="delete_all">Slette alle</string>
@ -424,4 +425,12 @@ Takk til: </string>
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Wybierz zdjęcie…</string>
<string name="clear">Czyste</string>
<string name="microphone">Mikrofon</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Proszę, powiedz coś</string>
<string name="speech_not_supported">Przepraszamy! Twoje urządzenie nie obsługuje wprowadzenia głosowego!</string>
<string name="delete_all">Usuń wszystko</string>
@ -432,4 +433,12 @@ Dzięki: </string>
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Selecione uma imagem…</string>
<string name="clear">Limpar</string>
<string name="microphone">Microfone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Por favor, diga algo</string>
<string name="speech_not_supported">Desculpe! Seu aparelho não suporta entrada por voz!</string>
<string name="delete_all">Excluir tudo</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Selectează o imagine…</string>
<string name="clear">Elimină</string>
<string name="microphone">Microfon</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Te rog, spune ceva</string>
<string name="speech_not_supported">Ne pare rău! Dispozitivul nu permite înregistrare vocală!</string>
<string name="delete_all">Șterge tot</string>
@ -432,4 +433,12 @@ Vă mulțumesc:
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -435,4 +436,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Одаберите слику…</string>
<string name="clear">Очисти</string>
<string name="microphone">Микрофон</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Реците нешто</string>
<string name="speech_not_supported">Ваш уређај не подржава гласовни унос!</string>
<string name="delete_all">Избриши све</string>
@ -343,7 +344,7 @@
<string name="request_sent">Захтев послат</string>
<string name="followed_by">Прати Вас</string>
<string name="action_search">Претрага</string>
<string name="set_capitalize">First letter in capital for replies</string>
<string name="set_capitalize">Прво слово велико у одговорима</string>
<!-- Quick settings for notifications -->
<string name="settings_popup_title">Гурни обавештења</string>
<string name="settings_popup_message">
@ -429,10 +430,18 @@
- Ако ништа ни даље не ради, пријавите нам проблем на Github-у, на https://github.com/stom79/mastalab/issues
</string>
<string name="media_ready">Мултимедија је учитана. Кликните овде да је прикажете.</string>
<string name="data_export_start">This action can be quite long. You will be notified when it will be finished.</string>
<string name="data_export_running">Still running, please wait…</string>
<string name="data_export">Export statuses</string>
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<string name="data_export_start">Ова акција може да потраје. Бићете обавештени када се заврши.</string>
<string name="data_export_running">Још увек се извршава, сачекајте…</string>
<string name="data_export">Статуси извоза</string>
<string name="data_export_toots">Статуси извоза за %1$s</string>
<string name="data_export_success">Извежено %1$s од укупно %2$s тутова.</string>
<string name="data_export_error">Дошло је до грешке приликом извоза података за %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -432,4 +433,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Resim seç…</string>
<string name="clear">Temiz</string>
<string name="microphone">Mikrofon</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Lütfen birşey söyleyin</string>
<string name="speech_not_supported">Üzgünüz! aygıtınız ses girişini desteklemiyor!</string>
<string name="delete_all">Tümünü sil</string>
@ -425,4 +426,12 @@ Teşekkürler: </string>
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -435,4 +436,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">Chọn ảnh…</string>
<string name="clear">Dọn dẹp</string>
<string name="microphone">Micrô</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Xin vui lòng, nói điều gì đó</string>
<string name="speech_not_supported">Lấy làm tiếc! Thiết bị của bạn không hỗ trợ nhập bằng giọng nói!</string>
<string name="delete_all">Xóa hết</string>
@ -427,4 +428,12 @@ Cảm ơn bạn: </string>
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -40,6 +40,7 @@
<string name="choose_picture">选择图片…</string>
<string name="clear">清理</string>
<string name="microphone">麦克风</string>
<string name="camera">Camera</string>
<string name="speech_prompt">请说点什么</string>
<string name="speech_not_supported">抱歉! 您的设备不支持语音输入!</string>
<string name="delete_all">删除全部</string>
@ -424,4 +425,12 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
</resources>

View File

@ -41,6 +41,7 @@
<string name="choose_picture">Select a picture…</string>
<string name="clear">Clean</string>
<string name="microphone">Microphone</string>
<string name="camera">Camera</string>
<string name="speech_prompt">Please, say something</string>
<string name="speech_not_supported">Sorry! Your device does not support the voice input!</string>
<string name="delete_all">Delete all</string>
@ -474,4 +475,16 @@
<string name="data_export_toots">Export statuses for %1$s</string>
<string name="data_export_success">%1$s toots out of %2$s have been exported.</string>
<string name="data_export_error">Something went wrong when exporting data for %1$s</string>
<!-- Proxy -->
<string name="proxy_set">Proxy</string>
<string name="proxy_type">Type</string>
<string name="proxy_enable">Enable proxy?</string>
<string name="poxy_host">Host</string>
<string name="poxy_port">Port</string>
<string name="poxy_login">Login</string>
<string name="poxy_password">Password</string>
<string-array translatable="false" name="proxy_type">
<item>HTTP</item>
<item>SOCKS</item>
</string-array>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/fr.gouv.etalab.mastodon/files/Pictures" />
</paths>