From cd367985b96884f3c47f535d924cceb0672446b0 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 21 Jan 2018 03:00:56 +0100 Subject: [PATCH 01/95] New translations strings.xml (Japanese) --- app/src/main/res/values-ja/strings.xml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index c8a16cee0..9399df59e 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -40,7 +40,7 @@ 画像を選択… 削除 マイク - Camera + カメラ 何か話してみてください お使いのデバイスは音声入力をサポートしておりません! すべて削除 @@ -417,17 +417,17 @@ メディアが読み込まれました。表示するにはここをクリックします。 This action can be quite long. You will be notified when it will be finished. - Still running, please wait… - Export statuses + 実行中です。お待ちください... + エクスポート ステータス Export statuses for %1$s %1$s toots out of %2$s have been exported. - Something went wrong when exporting data for %1$s + %1$s のデータをエクスポート中に問題が発生しました - Proxy - Type - Enable proxy? - Host - Port - Login - Password + プロキシ + タイプ + プロキシの有効化 + ホスト + ポート + ログイン + パスワード From 0fcfc69ab5e228b3a5dad7c38beff55027d9f60e Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 21 Jan 2018 03:10:54 +0100 Subject: [PATCH 02/95] New translations strings.xml (Japanese) --- app/src/main/res/values-ja/strings.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 9399df59e..68cff7ac6 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -117,7 +117,7 @@ コピー 共有 メンション - Timed mute + 時限ミュート このアカウントをミュートしますか? このアカウントをブロックしますか? @@ -196,9 +196,9 @@ スケジュールされた日付は現在の時間より後でなければなりません! バッテリーセーバーが有効になっています! 期待どおりに動作しない可能性があります。 - The time for muting should be greater than one minute. - %1$s has been muted until %2$s.\n You can unmute this account from his/her profile page. - %1$s is muted until %2$s.\n Click here to unmute the account. + ミュートする時間(1分超)です。 + %1$s は %2$s までミュートされています。\n このアカウントのプロフィールページでミュートを解除することができます。 + %1$s は %2$s までミュートされます。\n ミュートを解除するにはここをクリックします。 通知はありません あなたにメンションしました @@ -416,9 +416,9 @@ - もしまだ解決しない場合、Github(https://github.com/stom79/mastalab/issues)にissueを投稿してください メディアが読み込まれました。表示するにはここをクリックします。 - This action can be quite long. You will be notified when it will be finished. + この操作には時間がかかることがあります。完了すると通知されます。 実行中です。お待ちください... - エクスポート ステータス + トゥートをエクスポート Export statuses for %1$s %1$s toots out of %2$s have been exported. %1$s のデータをエクスポート中に問題が発生しました From f85507765c7aff495d7bc95cef28feb92810a63c Mon Sep 17 00:00:00 2001 From: stom79 Date: Sun, 21 Jan 2018 09:11:36 +0100 Subject: [PATCH 03/95] Fixes issue #263 - Duplicate videos in conversations --- .../fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index dd39511e5..23d4f63e6 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -940,7 +940,6 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct new RetrieveFeedsAsyncTask(context, RetrieveFeedsAsyncTask.Type.ONESTATUS, status.getId(),null, false,false, StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }); - if( position == conversationPosition){ if( theme == Helper.THEME_LIGHT) holder.main_container.setBackgroundResource(R.color.mastodonC3_); @@ -993,6 +992,8 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct } }else { + holder.status_cardview.setVisibility(View.GONE); + holder.status_cardview_video.setVisibility(View.GONE); if( theme == Helper.THEME_LIGHT) holder.main_container.setBackgroundResource(R.color.mastodonC3__); else From 985e03fb728f79dd44aa4f442ee6d7765e9dae34 Mon Sep 17 00:00:00 2001 From: stom79 Date: Sun, 21 Jan 2018 09:38:03 +0100 Subject: [PATCH 04/95] Fixes another bug related to #263 --- .../mastodon/drawers/StatusListAdapter.java | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index 23d4f63e6..fbe3bda91 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -90,12 +90,14 @@ 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.asynctasks.PostActionAsyncTask; +import fr.gouv.etalab.mastodon.asynctasks.RetrieveCardAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveFeedsAsyncTask; import fr.gouv.etalab.mastodon.asynctasks.RetrieveRepliesAsyncTask; import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.APIResponse; import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Attachment; +import fr.gouv.etalab.mastodon.client.Entities.Card; import fr.gouv.etalab.mastodon.client.Entities.Emojis; import fr.gouv.etalab.mastodon.client.Entities.Error; import fr.gouv.etalab.mastodon.client.Entities.Status; @@ -103,6 +105,7 @@ import fr.gouv.etalab.mastodon.fragments.DisplayStatusFragment; import fr.gouv.etalab.mastodon.helper.CrossActions; import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.interfaces.OnPostActionInterface; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveCardInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveEmojiInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveFeedsInterface; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRepliesInterface; @@ -119,7 +122,7 @@ import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor; * Created by Thomas on 24/04/2017. * Adapter for Status */ -public class StatusListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnRetrieveFeedsInterface, OnRetrieveEmojiInterface, OnRetrieveRepliesInterface { +public class StatusListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnRetrieveFeedsInterface, OnRetrieveEmojiInterface, OnRetrieveRepliesInterface, OnRetrieveCardInterface { private Context context; private List statuses; @@ -133,7 +136,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct private final int DISPLAYED_STATUS = 1; private int conversationPosition; private List timedMute; - + private int oldPosition; @@ -387,7 +390,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct @SuppressLint("SetJavaScriptEnabled") @Override - public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) { + public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) { if( viewHolder.getItemViewType() == DISPLAYED_STATUS){ final ViewHolder holder = (ViewHolder) viewHolder; @@ -931,13 +934,17 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct holder.status_content.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - new RetrieveFeedsAsyncTask(context, RetrieveFeedsAsyncTask.Type.ONESTATUS, status.getId(),null, false,false, StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + oldPosition = conversationPosition; + conversationPosition = position; + new RetrieveCardAsyncTask(context, status.getId(), StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }); holder.main_container.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - new RetrieveFeedsAsyncTask(context, RetrieveFeedsAsyncTask.Type.ONESTATUS, status.getId(),null, false,false, StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + oldPosition = conversationPosition; + conversationPosition = position; + new RetrieveCardAsyncTask(context, status.getId(), StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }); if( position == conversationPosition){ @@ -1489,31 +1496,24 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct @Override public void onRetrieveFeeds(APIResponse apiResponse) { - if( apiResponse.getError() != null){ - final SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); - boolean show_error_messages = sharedpreferences.getBoolean(Helper.SET_SHOW_ERROR_MESSAGES, true); - if( show_error_messages) - Toast.makeText(context, apiResponse.getError().getError(),Toast.LENGTH_LONG).show(); + + } + + + @Override + public void onRetrieveAccount(Card card) { + if( card == null){ return; } - - if( type == RetrieveFeedsAsyncTask.Type.CONTEXT && apiResponse.getStatuses().size() == 1){ - int oldPosition = conversationPosition; - int newPosition = 0; - for(Status status: statuses){ - if(status.getId().equals(apiResponse.getStatuses().get(0).getId())){ - conversationPosition = newPosition; - break; - } - newPosition++; - } - if( oldPosition < statuses.size()) - statusListAdapter.notifyItemChanged(oldPosition); - if( conversationPosition < statuses.size()) - statusListAdapter.notifyItemChanged(conversationPosition); - } + if( conversationPosition < this.statuses.size()) + this.statuses.get(conversationPosition).setCard(card); + if( oldPosition < this.statuses.size()) + statusListAdapter.notifyItemChanged(oldPosition); + if( conversationPosition < this.statuses.size()) + statusListAdapter.notifyItemChanged(conversationPosition); } + @Override public void onPostAction(int statusCode, API.StatusAction statusAction, String targetedId, Error error) { From e7fdc8ccc0e1c97b818f7acb9e81715ab1e1b26f Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 21 Jan 2018 09:51:26 +0100 Subject: [PATCH 05/95] New translations strings.xml (French) --- app/src/main/res/values-fr/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index b65d9c96a..b1208e8b0 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -40,7 +40,7 @@ Changer l\'image… Nettoyer Microphone - Camera + Appareil photo Veuillez dire quelque chose Désolé ! Votre appareil ne supporte pas la commande vocale ! Tout effacer @@ -434,9 +434,9 @@ Proxy Type - Enable proxy? - Host + Activer le proxy ? + Serveur Port - Login - Password + Identifiant + Mot de passe From 02a259df1c49bf604ca71f1f477273936b1f1217 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 21 Jan 2018 10:51:07 +0100 Subject: [PATCH 06/95] New translations strings.xml (Basque) --- app/src/main/res/values-eu/strings.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 64bbd898c..2c26ed0e1 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -40,7 +40,7 @@ Hautatu irudi bat… Garbitu Mikrofonoa - Camera + Kamera Esan zerbait Zure gailuak ez du onartzen ahots sarrera! Ezabatu guztiak @@ -433,11 +433,11 @@ Eskerrik asko Stéphane logoagatik. %1$s toot esportatu dira %2$stik. Zerbait ez da behar bezala joan %1$s(e)ko datuak esportatzean - Proxy - Type - Enable proxy? - Host - Port - Login - Password + Proxya + Mota + Gaitu proxya? + Ostalaria + Ataka + Saioa + Pasahitza From ec08d3a25a0df6484e9cd57d6f511448fa86ba77 Mon Sep 17 00:00:00 2001 From: stom79 Date: Sun, 21 Jan 2018 11:34:00 +0100 Subject: [PATCH 07/95] Fixes an issue with card --- .../etalab/mastodon/drawers/StatusListAdapter.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index fbe3bda91..d5eaa50a1 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -390,7 +390,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct @SuppressLint("SetJavaScriptEnabled") @Override - public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) { + public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) { if( viewHolder.getItemViewType() == DISPLAYED_STATUS){ final ViewHolder holder = (ViewHolder) viewHolder; @@ -935,7 +935,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct @Override public void onClick(View v) { oldPosition = conversationPosition; - conversationPosition = position; + conversationPosition = holder.getAdapterPosition();; new RetrieveCardAsyncTask(context, status.getId(), StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }); @@ -943,7 +943,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct @Override public void onClick(View v) { oldPosition = conversationPosition; - conversationPosition = position; + conversationPosition = holder.getAdapterPosition();; new RetrieveCardAsyncTask(context, status.getId(), StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }); @@ -1502,10 +1502,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct @Override public void onRetrieveAccount(Card card) { - if( card == null){ - return; - } - if( conversationPosition < this.statuses.size()) + if( conversationPosition < this.statuses.size() && card != null) this.statuses.get(conversationPosition).setCard(card); if( oldPosition < this.statuses.size()) statusListAdapter.notifyItemChanged(oldPosition); From 3f2fcfd966927ccd733858e8854a5022fd876b69 Mon Sep 17 00:00:00 2001 From: stom79 Date: Sun, 21 Jan 2018 17:30:39 +0100 Subject: [PATCH 08/95] clean --- .../fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index d5eaa50a1..08111ea83 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -935,7 +935,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct @Override public void onClick(View v) { oldPosition = conversationPosition; - conversationPosition = holder.getAdapterPosition();; + conversationPosition = holder.getAdapterPosition(); new RetrieveCardAsyncTask(context, status.getId(), StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }); @@ -943,7 +943,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct @Override public void onClick(View v) { oldPosition = conversationPosition; - conversationPosition = holder.getAdapterPosition();; + conversationPosition = holder.getAdapterPosition(); new RetrieveCardAsyncTask(context, status.getId(), StatusListAdapter.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }); From 564a5dd8993c0219f3bb155a430792c7055472bd Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 22 Jan 2018 14:53:25 +0100 Subject: [PATCH 09/95] New translations strings.xml (Serbian (Cyrillic)) --- app/src/main/res/values-sr/strings.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 439673dec..a96389735 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -40,7 +40,7 @@ Одаберите слику… Очисти Микрофон - Camera + Камера Реците нешто Ваш уређај не подржава гласовни унос! Избриши све @@ -437,11 +437,11 @@ Извежено %1$s од укупно %2$s тутова. Дошло је до грешке приликом извоза података за %1$s - Proxy - Type - Enable proxy? - Host - Port - Login - Password + Прокси + Тип + Омогући прокси? + Домаћин + Порт + Пријава + Лозинка From 66e19d9ebd2834cf6b91010c51b4e49622022790 Mon Sep 17 00:00:00 2001 From: stom79 Date: Mon, 22 Jan 2018 15:48:40 +0100 Subject: [PATCH 10/95] Fixes issue #238 - Automatic refresh of the home timeline --- .../fr/gouv/etalab/mastodon/activities/BaseMainActivity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java index 18de180e3..03d5e4103 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java @@ -1666,8 +1666,7 @@ public abstract class BaseMainActivity extends BaseActivity public void startSreaming(){ SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); boolean liveNotifications = sharedpreferences.getBoolean(Helper.SET_LIVE_NOTIFICATIONS, true); - boolean notify = sharedpreferences.getBoolean(Helper.SET_NOTIFY, true); - if( notify && liveNotifications) { + if( liveNotifications) { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); assert manager != null; for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { From 15a0b444c0513c77479df704a5ed19d41a5f035e Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 23 Jan 2018 07:01:03 +0100 Subject: [PATCH 11/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 444 +++++++++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 app/src/main/res/values-hy/strings.xml diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml new file mode 100644 index 000000000..b9c7c5e6e --- /dev/null +++ b/app/src/main/res/values-hy/strings.xml @@ -0,0 +1,444 @@ + + + + Open the menu + Close the menu + About + About the instance + Privacy + Cache + Logout + Login + + Close + Yes + No + Cancel + Download + Download %1$s + Download complete + Save %1$s + Media saved + File: %1$s + Password + Email + Accounts + Toots + Tags + Token + Save + Restore + Two-step authentication? + Other instance than mastodon.etalab.gouv.fr? + No results! + Instance + Instance: mastodon.social + Now works with the account %1$s + Add an account + The content of the toot has been copied to the clipboard + Change + Select a picture… + Clean + Microphone + Camera + Please, say something + Sorry! Your device does not support the voice input! + Delete all + Translate this toot. + Schedule + Text and icon sizes + Change the current text size: + Change the current icon size: + Next + Previous + Open with + Validate + Media + Share with + Shared via Mastalab + Replies + User name + Drafts + New data are available! Do you want to display them? + Favourites + New followers + Mentions + Boosts + Show boosts + Show replies + Open in browser + Translate + Please, wait few seconds before making this action. + + Home + Local timeline + Federated timeline + Options + Favourites + Communication + Muted users + Blocked users + Remote follow + Notifications + Follow requests + Optimization + Settings + Profile + What do you want to do? + Delete an account + Delete the account %1$s from the application? + Send an email + Please select a file + No file explorer found! + Click on the path to change it + Failed! + Scheduled toots + Information below may reflect the user\'s profile incompletely. + Insert emoji + The app did not collect custom emojis for the moment. + Live notifications + + No toot to display + The toot was added to favourites + The toot was removed from favourites! + The toot was boosted! + The toot is no longer boosted! + Boosted by %1$s + Add this toot to your favourites? + Remove this toot from your favourites? + Boost this toot? + Unboost this toot? + Pin this toot? + Unpin this toot? + Mute + Block + Report + Remove + Copy + Share + Mention + Timed mute + + Mute this account? + Block this account? + Report this toot? + + + Remove this toot? + + + %d reply + %d replies + + + %d s + %d m + %d h + %d d + + Warning + What is on your mind? + TOOT! + cw + Write a toot + Reply to a toot + You have reached the 500 characters allowed! + Select a media + An error occurred while selecting the media! + Delete this media? + Your toot is empty! + Visibility of the toot + Visibility of the toots by default: + The toot has been sent! + You are replying to this toot: + Sensitive content? + + Post to public timelines + Do not post to public timelines + Post to followers only + Post to mentioned users only + + No draft! + Choose a toot + Choose an account + Select some accounts + Remove draft? + Click on the button to display the original toot + Describe for the visually impaired + + No description available! + + Release %1$s + Developer: + License: + GNU GPL V3 + Source code: + Translation of toots: + Search instances: + instances.social + Icon designer: + + Conversation + + No account to display + No follow request + Toots \n %1$s + Following \n %1$s + Followers \n %1$s + Pinned \n %d + Authorize + Reject + + No scheduled toot to display! + Write a toot and then choose Schedule from the top menu. + Delete scheduled toot? + Media: %d + The toot has been scheduled! + The scheduled date must be greater than the current hour! + Battery saver is enabled! It might not work as expected. + + The time for muting should be greater than one minute. + %1$s has been muted until %2$s.\n You can unmute this account from his/her profile page. + %1$s is muted until %2$s.\n Click here to unmute the account. + + No notification to display + mentioned you + boosted your status + favourited your status + followed you + New toot from %1$s + + and another notification + and %d other notifications + + + and another toot to discover + and %d other toots to discover + + Delete a notification? + Delete all notifications? + The notification has been deleted! + All notifications have been deleted! + + Following + Followers + Pinned + + Unable to get client id! + No Internet connection! + The account was blocked! + The account is no longer blocked! + The account was muted! + The account is no longer muted! + The account was followed! + The account is no longer followed! + The toot was boosted! + The toot is no longer boosted! + The toot was added to your favourites! + The toot was removed from your favourites! + The toot was reported! + The toot was deleted! + The toot was pinned! + The toot was unpinned! + Oops ! An error occurred! + An error occurred! The instance did not return an authorisation code! + The instance domain does not seem to be valid! + An error occurred while switching between accounts! + An error occurred while searching! + Can not log in! + The profile data have been saved! + No action can be taken + The media has been saved! + An error occurred while translating! + Draft saved! + Are you sure this instance allows this number of characters? Usually, this value is close to 500 characters. + Visibility of the toots has been changed for the account %1$s + Instance name and screen name cannot be blank! + + Optimisation of loading + Number of toots per load + Number of accounts per load + Number of notifications per load + Always + WIFI + Ask + Load the media + Load the pictures + Show more… + Show less… + Sensitive content + Display previous message in responses + Display local timeline + Display federated timeline + Disable GIF avatars + Path: + Save drafts automatically + Display counters + Add URL of media in toots + Manage notifications + Notify when someone follows you + Notify when someone requests to follow you + Notify when someone boosts your status + Notify when someone favourites your status + Notify when someone mentions you + Show confirmation dialog before boosting + Show confirmation dialog before adding to favourites + Advanced settings + Notify in WIFI only + Notify? + Silent Notifications + Night mode + NSFW view timeout (seconds, 0 means off) + Edit profile + Bio… + Save changes + Choose a header picture + Display the number of replies in home timeline + Display profile pictures? + Allow interactions between accounts? + You have reached the 160 characters allowed! + You have reached the 30 characters allowed! + Time slot for notifications: + Between + and + The time must be greater than %1$s + The time must be lower than %1$s + Start time + End time + Use the built-in browser + Enable Javascript + Allow third-party cookies + Layout for timelines: + + Tabs + Menu + Tabs and menu + + + Yandex + No + + Set LED colour: + + Blue + Cyan + Magenta + Green + Red + Yellow + White + + News + Notify for new toots on the home timeline + Display error messages + Follow + Unfollow + Block + Unblock + Mute + No action + Unmute + Request sent + Follows you + Search + First letter in capital for replies + + Push notifications + + Please, confirm push notifications that you want to receive. + You can enable or disable these notifications later in settings (Notifications tab). + + For unread toots in home time-line? + For unread notifications? + + Clear cache + There are %1$s of data in cache.\n\nWould you like to delete them? + Mb + Cache was cleared! %1$s were released + + Recorded data + + Only basic information from accounts are stored on the device. + These data are strictly confidential and can only be used by the application. + Deleting the application immediately removes these data.\n + ⚠ Login and passwords are never stored. They are only used during a secure authentication (SSL) with an instance. + + Permissions: + + - ACCESS_NETWORK_STATE: Used to detect if the device is connected to a WIFI network.\n + - INTERNET: Used for queries to an instance.\n + - WRITE_EXTERNAL_STORAGE: Used to store media or to move the app on a SD card.\n + - READ_EXTERNAL_STORAGE: Used to add media to toots.\n + - BOOT_COMPLETED: Used to start the notification service.\n + - WAKE_LOCK: Used during the notification service. + + API permissions: + + - Read: Read data.\n + - Write: Post statuses and upload media for statuses.\n + - Follow: Follow, unfollow, block, unblock.\n\n + ⚠ These actions are carried out only when user requests them. + + Tracking and Libraries + + The application does not use tracking tools (audience measurement, error reporting, etc.) and does not contain any advertising.\n\n + The use of libraries is minimized: \n + - Glide: To manage media\n + - Android-Job: To manage services\n + - PhotoView: To manage images\n + + Translation of toots + + The application offers the ability to translate toots using the locale of the device and the Yandex API.\n + Yandex has its proper privacy-policy which can be found here: https://yandex.ru/legal/confidential/?lang=en + + + Thank you to Stéphane for the logo. + + + Thank you to: + + Filter out by regular expressions + Search + Delete + Fetch more toots… + + Lists + Are you sure you want to permanently delete this list? + There is nothing in this list yet. When members of this list post new statuses, they will appear here. + Add to list + Remove from list + Add list + Delete list + Edit list + New list title + Search among people you follow + Your lists + + %1$s has moved to %2$s + Show boosts/favourites count + Authentication does not work? + + Here are some checks that might help:\n\n + - Check there is no spelling mistakes in the instance name\n\n + - Check that your instance is not down\n\n + - If you use the two-factor authentication (2FA), please use the link at the bottom (once the instance name is filled)\n\n + - You can also use this link without using the 2FA\n\n + - If it still does not work, please raise an issue on Github at https://github.com/stom79/mastalab/issues + + Media has been loaded. Click here to display it. + This action can be quite long. You will be notified when it will be finished. + Still running, please wait… + Export statuses + Export statuses for %1$s + %1$s toots out of %2$s have been exported. + Something went wrong when exporting data for %1$s + + Proxy + Type + Enable proxy? + Host + Port + Login + Password + From a97d919f1dfd823731ca0684bb9a739ae2fe38c8 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 23 Jan 2018 14:53:17 +0100 Subject: [PATCH 12/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index b9c7c5e6e..522d617af 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -1,7 +1,7 @@ - Open the menu + Բացել մենյուն Close the menu About About the instance From 701967d2abb8d8509b7746ec4b85f813504a3e68 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 23 Jan 2018 15:03:40 +0100 Subject: [PATCH 13/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 52 +++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 522d617af..dbd24b913 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -2,34 +2,34 @@ Բացել մենյուն - Close the menu - About + Փակել մենյուն + Տեղեկություններ About the instance - Privacy - Cache - Logout - Login + Գաղտնիություն + Քեշ + Ելք + Մուտք - Close - Yes - No - Cancel - Download - Download %1$s - Download complete - Save %1$s - Media saved - File: %1$s - Password - Email - Accounts - Toots - Tags - Token - Save - Restore - Two-step authentication? - Other instance than mastodon.etalab.gouv.fr? + Փակել + Այո + Ոչ + Չեղարկել + Ներբեռնել + Ներբեռնել %1$s-ը + Ներբեռնումն ավարտված է + Պահել %1$s-ը + Մեդիան պահված է + Նիշք․ %1$s + Գաղտնաբառ + Էլփոստ + Հաշիվներ + Թութեր + Պիտակներ + Կտրոն + Պահել + Վերականգնել + Երկքայլ վավերացու՞մ + mastodon.etalab.gouv.fr-ից տարբեր հանգու՞յց No results! Instance Instance: mastodon.social From 910b1ddb4f853d6aa7235658af9820367a55a285 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 23 Jan 2018 15:14:30 +0100 Subject: [PATCH 14/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 42 +++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index dbd24b913..f188115bc 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -30,27 +30,27 @@ Վերականգնել Երկքայլ վավերացու՞մ mastodon.etalab.gouv.fr-ից տարբեր հանգու՞յց - No results! - Instance - Instance: mastodon.social - Now works with the account %1$s - Add an account - The content of the toot has been copied to the clipboard - Change - Select a picture… - Clean - Microphone - Camera - Please, say something - Sorry! Your device does not support the voice input! - Delete all - Translate this toot. - Schedule - Text and icon sizes - Change the current text size: - Change the current icon size: - Next - Previous + Ոչ մի արդյունք! + Հանգույց + Հանգույց․ mastodon.social + Օգտագեծվող հաշիվ՝ %1$s + Ավելացնել հաշիվ + Թութի բովանդակությունը պատճենվել է սեղմատախտակին + Փոխել + Ընտրել նկար… + Մաքրել + Խոսափող + Խցիկ + Ինչ-որ բան ասա + Ներիր։ Քո սարքը չի աջակցում ձայնային մուտքագրում։ + Ջնջել ամենը + Թարգմանել այս թութը։ + Օրակարգ + Տեքստի և պատկերակների չափսերը + Փոխել տեքստի ներկայիս չափսը․ + Փոխել պատկերակի ներկայիս չափսը․ + Հաջորդը + Նախորդը Open with Validate Media From 044c5d7856921967159e87294b8ba3e9c74318fb Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 23 Jan 2018 15:33:08 +0100 Subject: [PATCH 15/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 76 +++++++++++++------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index f188115bc..5b19438e1 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -51,7 +51,7 @@ Փոխել պատկերակի ներկայիս չափսը․ Հաջորդը Նախորդը - Open with + Բացել այլ հավելվածով Validate Media Share with @@ -103,53 +103,53 @@ The toot was removed from favourites! The toot was boosted! The toot is no longer boosted! - Boosted by %1$s - Add this toot to your favourites? - Remove this toot from your favourites? - Boost this toot? - Unboost this toot? - Pin this toot? - Unpin this toot? - Mute - Block - Report - Remove - Copy - Share - Mention - Timed mute + Խրախուսվել է %1$s-ի կողմից + Ավելացնե՞լ այս թութը քո ընտրայլներում + Հեռացնե՞լ այս թութը քո ընտրյալներից։ + Խրախուսե՞լ այս թութը։ + Ապախրախուսե՞լ այս թութը։ + Մեխե՞լ այս թութը։ + Արձակե՞լ այս թութը։ + Խլացնել + Արգելափակել + Ահազանգել + Հեռացնել + Պատճենել + Տարածել + Հիշատակել + Ժամանակավոր խլացում - Mute this account? - Block this account? - Report this toot? + Խլացնե՞լ այս հաշիվը + Արգելափակե՞լ այս հաշիվը + Ահազանգե՞լ այս հաշվի մասին - Remove this toot? + Հեռացնե՞լ այս թութը %d reply - %d replies + %d արձագանք - %d s - %d m - %d h - %d d + %d վրկ + %d ր + %d ժ + %d օր - Warning - What is on your mind? - TOOT! + Զգուշացում + Մտքիդ ի՞նչ կա + ԹՈՒԹԵԼ! cw - Write a toot - Reply to a toot - You have reached the 500 characters allowed! - Select a media - An error occurred while selecting the media! - Delete this media? - Your toot is empty! - Visibility of the toot - Visibility of the toots by default: - The toot has been sent! + Թութ գրել + Արձագանքել թութին + Մոտեցել ես 500 նիշ սահմանափակմանը + Ընտրել մեդիա + Մեդիան ընտրելու ընթացքում սխալ է հայտնվել + Ջնջե՞լ այս մեդիան + Քո թութը դատարկ է + Թութի տեսանելիությունը + Թութերի սկզբնադիր տեսանելիությունը՝ + Թութն ուղարկված է You are replying to this toot: Sensitive content? From c78d5f6faeb7bcb2d9dc6de6205164913ae4fead Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 23 Jan 2018 15:34:43 +0100 Subject: [PATCH 16/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 5b19438e1..cd0436196 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -150,7 +150,7 @@ Թութի տեսանելիությունը Թութերի սկզբնադիր տեսանելիությունը՝ Թութն ուղարկված է - You are replying to this toot: + Արձագանքում ես տվյալ թութին․ Sensitive content? Post to public timelines From c8963df1a8dc657bd6f46326cc69464da5d658e3 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 23 Jan 2018 15:42:52 +0100 Subject: [PATCH 17/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index cd0436196..259b52006 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -151,7 +151,7 @@ Թութերի սկզբնադիր տեսանելիությունը՝ Թութն ուղարկված է Արձագանքում ես տվյալ թութին․ - Sensitive content? + Զգայուն բովանդակությու՞ն Post to public timelines Do not post to public timelines From 7e299f3c5b34a5ea9f4cab13b387203196bea356 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 10:12:06 +0100 Subject: [PATCH 18/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 259b52006..a2fe3bdc4 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -4,7 +4,7 @@ Բացել մենյուն Փակել մենյուն Տեղեկություններ - About the instance + Հանգույցի մասին Գաղտնիություն Քեշ Ելք @@ -52,13 +52,13 @@ Հաջորդը Նախորդը Բացել այլ հավելվածով - Validate - Media + Վավերացնել + Մեդիա Share with - Shared via Mastalab - Replies - User name - Drafts + Տարածել Մաստալաբով + Արձագանքներ + Օգտանուն + Սևագրեր New data are available! Do you want to display them? Favourites New followers From 03d25ebb523796293a9b1e2d60eac2bdb21a1372 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 10:22:35 +0100 Subject: [PATCH 19/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index a2fe3bdc4..bfa9b7c24 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -59,18 +59,18 @@ Արձագանքներ Օգտանուն Սևագրեր - New data are available! Do you want to display them? - Favourites - New followers - Mentions - Boosts - Show boosts - Show replies - Open in browser - Translate - Please, wait few seconds before making this action. + Թարմ տվյալներն հասանելի են։ Ուզու՞մ ես դրանք տեսնել + Նախընտրություններ + Նոր հետևորդներ + Հիշատակումներ + Խրախուսումներ + Ցուցադրել խրախ-ները + Ցուցադրել արձագանքները + Բացել զննիչում + Թարգմանել + Սպասիր մի քանի վայրկյան մինչև այս գործողութ-նը կատարելը։ - Home + Տուն Local timeline Federated timeline Options @@ -104,8 +104,8 @@ The toot was boosted! The toot is no longer boosted! Խրախուսվել է %1$s-ի կողմից - Ավելացնե՞լ այս թութը քո ընտրայլներում - Հեռացնե՞լ այս թութը քո ընտրյալներից։ + Ավելացնե՞լ այս թութը նախընտրություններին + Հեռացնե՞լ այս թութը Նախընտրություններից Խրախուսե՞լ այս թութը։ Ապախրախուսե՞լ այս թութը։ Մեխե՞լ այս թութը։ From 5ea44f2a025f40dcf500f1904b560e2ef91a5594 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 10:32:56 +0100 Subject: [PATCH 20/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index bfa9b7c24..fe4978e8f 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -73,16 +73,16 @@ Տուն Local timeline Federated timeline - Options - Favourites - Communication - Muted users - Blocked users - Remote follow - Notifications - Follow requests - Optimization - Settings + Ընտրանքներ + Նախընտրություններ + Հաղորդակցում + Խլացված օգտատերեր + Արգելափակված օգտատերեր + Հետևել հեռակա + Ծանուցումներ + Հետևելու հայտեր + Լավարկում + Կարգավորումներ Profile What do you want to do? Delete an account From c5cc57e08c38148ca96c751141fe4d0be7ffe21a Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 10:44:30 +0100 Subject: [PATCH 21/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index fe4978e8f..449e31a2d 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -83,16 +83,16 @@ Հետևելու հայտեր Լավարկում Կարգավորումներ - Profile - What do you want to do? - Delete an account - Delete the account %1$s from the application? - Send an email - Please select a file - No file explorer found! - Click on the path to change it - Failed! - Scheduled toots + Էջ + Ի՞նչ ես ուզում անել + Ջնջել հաշիվ + Ջնջե՞լ %1$s հաշիվը հավելվածից + Ուղարկել էլփոստ + Ընտրիր նիշք + Ոչ մի նիշքախույզ չի հայտնաբերվել! + Կտտացրու հետագծի վրա՝ այն փոխելու համար + Ձախողում + Հերթագրված թութեր Information below may reflect the user\'s profile incompletely. Insert emoji The app did not collect custom emojis for the moment. From 5f0344936705b88f0e527ed2b42e3230ee09e9bb Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 10:51:14 +0100 Subject: [PATCH 22/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 449e31a2d..28f7fa820 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -93,9 +93,9 @@ Կտտացրու հետագծի վրա՝ այն փոխելու համար Ձախողում Հերթագրված թութեր - Information below may reflect the user\'s profile incompletely. - Insert emoji - The app did not collect custom emojis for the moment. + Սույն տեղեկատվությունը կարող է օգտատիրոջ էջն արտացոլել ոչ լիարժեք։ + Էմոջի ներմուծել + Ներկա պահին հավելվածը չունի հավաքագրած էմոջիներ։ Live notifications No toot to display From b126b9187c29aaf18bc1d43c0bfccc2fe0a43e2a Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 11:02:58 +0100 Subject: [PATCH 23/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 28f7fa820..f43b35321 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -96,13 +96,13 @@ Սույն տեղեկատվությունը կարող է օգտատիրոջ էջն արտացոլել ոչ լիարժեք։ Էմոջի ներմուծել Ներկա պահին հավելվածը չունի հավաքագրած էմոջիներ։ - Live notifications + Ուղիղ ծանուցումներ - No toot to display - The toot was added to favourites - The toot was removed from favourites! - The toot was boosted! - The toot is no longer boosted! + Թութ չկա + Թութն ավելացվել է նախընտրություններին + Թութը հեռացվել է նախընտրություններից + Թութը խրախուսվել է + Թութն այլևս խրախուսված չէ Խրախուսվել է %1$s-ի կողմից Ավելացնե՞լ այս թութը նախընտրություններին Հեռացնե՞լ այս թութը Նախընտրություններից @@ -155,14 +155,14 @@ Post to public timelines Do not post to public timelines - Post to followers only - Post to mentioned users only + Գրառել միայն հետևորդների համար + Գրառել միայն հիշատակված օգտատերերի համար - No draft! - Choose a toot - Choose an account - Select some accounts - Remove draft? + Ոչ մի սևագիր + Ընտրել թութ + Ընտրել հաշիվ + Ընտրել մի քանի հաշիվ + Հեռացնե՞լ սևագիրը Click on the button to display the original toot Describe for the visually impaired From 3184f375db45d55d15ad45d33eef780076c88618 Mon Sep 17 00:00:00 2001 From: stom79 Date: Wed, 24 Jan 2018 11:15:45 +0100 Subject: [PATCH 24/95] Fixes issue #265 - Resize pictures before upload --- .../mastodon/activities/TootActivity.java | 65 +++++++++++++++---- .../mastodon/client/Entities/Status.java | 4 +- .../mastodon/fragments/SettingsFragment.java | 27 +++++++- .../gouv/etalab/mastodon/helper/Helper.java | 5 ++ .../res/layout-sw600dp/fragment_settings.xml | 19 ++++++ app/src/main/res/layout/fragment_settings.xml | 19 ++++++ app/src/main/res/values/strings.xml | 9 +++ 7 files changed, 129 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java index 7e431eec6..1cd5dea76 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java @@ -89,8 +89,10 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.lang.ref.WeakReference; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -672,11 +674,22 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount } picture_scrollview.setVisibility(View.VISIBLE); try { + File photoFiletmp = createImageFile(false); InputStream inputStream = getContentResolver().openInputStream(fileUri); - toot_picture_container.setVisibility(View.VISIBLE); - picture_scrollview.setVisibility(View.VISIBLE); - toot_picture.setEnabled(false); - new HttpsConnection(TootActivity.this).upload(inputStream, TootActivity.this); + OutputStream output = new FileOutputStream(photoFile); + try { + byte[] buffer = new byte[4 * 1024]; // or other buffer size + int read; + + assert inputStream != null; + while ((read = inputStream.read(buffer)) != -1) { + output.write(buffer, 0, read); + } + output.flush(); + } finally { + output.close(); + } + new asyncPicture(TootActivity.this, photoFiletmp).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); count++; } catch (Exception e) { Toast.makeText(getApplicationContext(), R.string.toot_select_image_error, Toast.LENGTH_LONG).show(); @@ -699,7 +712,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // Create the File where the photo should go try { - photoFile = createImageFile(); + photoFile = createImageFile(true); } 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) { @@ -713,11 +726,11 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount } - private File createImageFile() throws IOException { + private File createImageFile(boolean external) 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 storageDir = external?getExternalFilesDir(Environment.DIRECTORY_PICTURES):getCacheDir(); File image = File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ @@ -741,9 +754,26 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount try { //noinspection ConstantConditions InputStream inputStream = getContentResolver().openInputStream(data.getData()); - toot_picture_container.setVisibility(View.VISIBLE); - toot_picture.setEnabled(false); - new HttpsConnection(TootActivity.this).upload(inputStream, TootActivity.this); + File photoFiletmp; + try { + photoFiletmp = createImageFile(false); + OutputStream output = new FileOutputStream(photoFiletmp); + try { + byte[] buffer = new byte[4 * 1024]; // or other buffer size + int read; + + assert inputStream != null; + while ((read = inputStream.read(buffer)) != -1) { + output.write(buffer, 0, read); + } + output.flush(); + new asyncPicture(TootActivity.this, photoFiletmp).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } finally { + output.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } } catch (FileNotFoundException e) { Toast.makeText(getApplicationContext(),R.string.toot_select_image_error,Toast.LENGTH_LONG).show(); toot_picture.setEnabled(true); @@ -756,9 +786,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount 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); - } } @@ -778,8 +806,17 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount Bitmap takenImage = BitmapFactory.decodeFile(String.valueOf(this.fileWeakReference.get())); int size = takenImage.getByteCount(); - //Resize image to 2 meg - double resize = ((double)size)/((double)16777216); + SharedPreferences sharedpreferences = this.activityWeakReference.get().getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); + int resizeSet = sharedpreferences.getInt(Helper.SET_PICTURE_RESIZE, Helper.S_1MO); + double resizeby = 1; + if( resizeSet == Helper.S_512KO){ + resizeby = 4194304; + }else if(resizeSet == Helper.S_1MO){ + resizeby = 8388608; + }else if(resizeSet == Helper.S_2MO){ + resizeby = 16777216; + } + double resize = ((double)size)/resizeby; Bitmap newBitmap; if( resize > 1 ){ newBitmap = Bitmap.createScaledBitmap(takenImage, (int)(takenImage.getWidth()/resize), diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java index 7e5178e6a..00502e71c 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java @@ -444,7 +444,7 @@ public class Status implements Parcelable{ public void makeClickable(Context context){ - if( ((Activity)context).isFinishing() ) + if( ((Activity)context).isFinishing() || status == null) return; SpannableString spannableStringContent, spannableStringCW; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) @@ -466,7 +466,7 @@ public class Status implements Parcelable{ public void makeClickableTranslation(Context context){ - if( ((Activity)context).isFinishing() ) + if( ((Activity)context).isFinishing() || status == null) return; SpannableString spannableStringTranslated; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/SettingsFragment.java b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/SettingsFragment.java index 11681642c..b00c49658 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/SettingsFragment.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/SettingsFragment.java @@ -70,7 +70,7 @@ public class SettingsFragment extends Fragment { private Context context; private static final int ACTIVITY_CHOOSE_FILE = 411; private TextView set_folder; - int count2 = 0; + int count1, count2 = 0; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -520,6 +520,7 @@ public class SettingsFragment extends Fragment { } }); + //Translators final Spinner translation_layout_spinner = rootView.findViewById(R.id.translation_layout_spinner); ArrayAdapter adapterTrans = ArrayAdapter.createFromResource(getContext(), R.array.settings_translation, android.R.layout.simple_spinner_item); @@ -569,8 +570,28 @@ public class SettingsFragment extends Fragment { } }); - - + //Resize + final Spinner resize_layout_spinner = rootView.findViewById(R.id.set_resize_picture); + ArrayAdapter adapterResize = ArrayAdapter.createFromResource(getContext(), + R.array.settings_resize_picture, android.R.layout.simple_spinner_item); + resize_layout_spinner.setAdapter(adapterResize); + int positionSpinnerResize = sharedpreferences.getInt(Helper.SET_PICTURE_RESIZE, Helper.S_1MO); + resize_layout_spinner.setSelection(positionSpinnerResize); + resize_layout_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + if( count1 > 0){ + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putInt(Helper.SET_PICTURE_RESIZE, position); + editor.apply(); + }else { + count1++; + } + } + @Override + public void onNothingSelected(AdapterView parent) { + } + }); return rootView; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java index f81d48ae3..2a392bc88 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java @@ -224,6 +224,11 @@ public class Helper { public static final String SET_LIVE_NOTIFICATIONS = "set_live_notifications"; public static final String SET_DISABLE_GIF = "set_disable_gif"; public static final String SET_CAPITALIZE = "set_capitalize"; + public static final String SET_PICTURE_RESIZE = "set_picture_resize"; + public static final int S_NONE = 0; + public static final int S_512KO = 1; + public static final int S_1MO = 2; + public static final int S_2MO = 3; public static final int ATTACHMENT_ALWAYS = 1; public static final int ATTACHMENT_WIFI = 2; public static final int ATTACHMENT_ASK = 3; diff --git a/app/src/main/res/layout-sw600dp/fragment_settings.xml b/app/src/main/res/layout-sw600dp/fragment_settings.xml index 75b4e7868..daaa1a261 100644 --- a/app/src/main/res/layout-sw600dp/fragment_settings.xml +++ b/app/src/main/res/layout-sw600dp/fragment_settings.xml @@ -142,6 +142,25 @@ android:text="@string/show_boost_count" android:layout_height="wrap_content" /> + + + + + + + + + + + + + No + + No + 512 Ko + 1 Mo + 2 Mo + + Set LED colour: @@ -366,6 +373,8 @@ Search First letter in capital for replies + Resize pictures + Push notifications From d974b0bc84c644612dd5ac1737f9b1102bb5b1fe Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 14:03:30 +0100 Subject: [PATCH 25/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index f43b35321..f6da6eac7 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -163,20 +163,20 @@ Ընտրել հաշիվ Ընտրել մի քանի հաշիվ Հեռացնե՞լ սևագիրը - Click on the button to display the original toot - Describe for the visually impaired + Կտտացրեւ կոճակին՝ բնօրինակ թութը տեսնելու համար + Նկարագրիր՝ տեսողության խնդիրներ ունեցողների համար - No description available! + Նկարագրություն չկա - Release %1$s - Developer: - License: + Թողարկում %1$s + Մշակող․ + Արտոնագիր․ GNU GPL V3 - Source code: - Translation of toots: - Search instances: + Սկզբնական կոդ․ + Թութերի թարգմանությունը․ + Փնտրել հանգույցներ․ instances.social - Icon designer: + Պատկերակի հեղինակ․ Conversation From f7f30296fac171dde89ae9a9e85037dd238ad662 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 14:12:34 +0100 Subject: [PATCH 26/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index f6da6eac7..a8931dad3 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -45,7 +45,7 @@ Ներիր։ Քո սարքը չի աջակցում ձայնային մուտքագրում։ Ջնջել ամենը Թարգմանել այս թութը։ - Օրակարգ + Հերթ Տեքստի և պատկերակների չափսերը Փոխել տեքստի ներկայիս չափսը․ Փոխել պատկերակի ներկայիս չափսը․ @@ -178,19 +178,19 @@ instances.social Պատկերակի հեղինակ․ - Conversation + Զրույց - No account to display - No follow request - Toots \n %1$s - Following \n %1$s - Followers \n %1$s - Pinned \n %d - Authorize - Reject + Ցուցադրելու հաշիվ չկա + Հետևելու հայտեր չկան + Թութեր \n %1$s + Ում ես հետևում \n %1$s + Հետևորդներ \n %1$s + Մեխեր \n %d + Թույլատրել + Մերժել - No scheduled toot to display! - Write a toot and then choose Schedule from the top menu. + Հերթագրված թութեր չկան + Թութ գրիր, հետո ընտրիր Հերթը գլխավոր մենյուից Delete scheduled toot? Media: %d The toot has been scheduled! From 34b869d7f550a4d82d88dcf54fbba74fef6aba19 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 14:24:04 +0100 Subject: [PATCH 27/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index a8931dad3..c39a061d7 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -191,19 +191,19 @@ Հերթագրված թութեր չկան Թութ գրիր, հետո ընտրիր Հերթը գլխավոր մենյուից - Delete scheduled toot? - Media: %d - The toot has been scheduled! - The scheduled date must be greater than the current hour! - Battery saver is enabled! It might not work as expected. + Ջնջե՞լ հերթագրված թութը + Մեդիա %d + Թութը հերթագրված է + Հերթագրման ամսաթիվը պետք է լինի ավելի ուշ քան ընթացիկ ժամը + Մարտկոցի տնտեսումը միացված է։ Հնարավոր է չաշխատի այնպես ինչպես ակնկալում եք - The time for muting should be greater than one minute. - %1$s has been muted until %2$s.\n You can unmute this account from his/her profile page. - %1$s is muted until %2$s.\n Click here to unmute the account. + Խլացնելու ժամանակահատվածը պետք է լինի 1 րոպեից ավել։ + %1$s-ը խլացվել է մինչև %2$s։ \n Կարող ես ապախլացնել հաշիվն իր էջից։ + %1$s-ը խլացվել է մինչև %2$s։ \n Կտտացրու այստեղ՝ ապխլացնելու համար։ - No notification to display - mentioned you - boosted your status + Ծանուցում չկա + Քեզ հիշատակել է + խրախուսել է քո թութը favourited your status followed you New toot from %1$s From 0f8a981b2f85851cb23921b852ea1b52376186e4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 14:31:58 +0100 Subject: [PATCH 28/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index c39a061d7..bb712414c 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -204,12 +204,12 @@ Ծանուցում չկա Քեզ հիշատակել է խրախուսել է քո թութը - favourited your status - followed you - New toot from %1$s + գրառումդ ավելացրել է նախընտրումներին + հետևում է քեզ + Նոր թութ %1$s-ից - and another notification - and %d other notifications + և մեկ այլ ծանուցում + և %d այլ ծանուցումներ and another toot to discover From b058df835380338689baceedf4d961999f39cfa8 Mon Sep 17 00:00:00 2001 From: stom79 Date: Wed, 24 Jan 2018 15:56:33 +0100 Subject: [PATCH 29/95] Allows onion urls --- .../activities/EditProfileActivity.java | 2 +- .../mastodon/activities/LoginActivity.java | 7 +- .../activities/RemoteFollowActivity.java | 2 +- .../activities/ShowAccountActivity.java | 4 +- .../activities/ShowConversationActivity.java | 2 +- .../mastodon/activities/TootActivity.java | 2 +- .../activities/WebviewConnectActivity.java | 4 +- .../RetrieveRemoteDataAsyncTask.java | 3 +- .../fr/gouv/etalab/mastodon/client/API.java | 2 +- .../mastodon/client/HttpsConnection.java | 1030 ++++++++++++----- .../gouv/etalab/mastodon/helper/Helper.java | 20 +- .../services/LiveNotificationService.java | 244 ++-- 12 files changed, 911 insertions(+), 411 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/EditProfileActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/EditProfileActivity.java index 71f266b00..9b0a422cf 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/EditProfileActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/EditProfileActivity.java @@ -138,7 +138,7 @@ public class EditProfileActivity extends BaseActivity implements OnRetrieveAccou Account account = new AccountDAO(getApplicationContext(),db).getAccountByID(userId); String url = account.getAvatar(); if( url.startsWith("/") ){ - url = "https://" + Helper.getLiveInstance(getApplicationContext()) + account.getAvatar(); + url = Helper.getLiveInstanceWithProtocol(getApplicationContext()) + account.getAvatar(); } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/LoginActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/LoginActivity.java index 3da6d105c..3a6e46a74 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/LoginActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/LoginActivity.java @@ -252,7 +252,7 @@ public class LoginActivity extends BaseActivity { @Override public void run() { try { - final String response = new HttpsConnection(LoginActivity.this).post("https://" + instance + action, 30, parameters, null ); + final String response = new HttpsConnection(LoginActivity.this).post(Helper.instanceWithProtocol(instance) + action, 30, parameters, null ); runOnUiThread(new Runnable() { public void run() { JSONObject resobj; @@ -274,11 +274,12 @@ public class LoginActivity extends BaseActivity { i.putExtra("instance", instance); startActivity(i); } - } catch (JSONException ignored) {} + } catch (JSONException ignored) {ignored.printStackTrace();} } }); } catch (final Exception e) { + e.printStackTrace(); runOnUiThread(new Runnable() { public void run() { String message; @@ -326,7 +327,7 @@ public class LoginActivity extends BaseActivity { @Override public void run() { try { - final String response = new HttpsConnection(LoginActivity.this).post("https://" + instance + "/oauth/token", 30, parameters, null ); + final String response = new HttpsConnection(LoginActivity.this).post(Helper.instanceWithProtocol(instance) + "/oauth/token", 30, parameters, null ); runOnUiThread(new Runnable() { public void run() { JSONObject resobj; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/RemoteFollowActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/RemoteFollowActivity.java index 6bb270488..325623f4d 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/RemoteFollowActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/RemoteFollowActivity.java @@ -144,7 +144,7 @@ public class RemoteFollowActivity extends BaseActivity implements OnRetrieveRemo Account account = new AccountDAO(getApplicationContext(),db).getAccountByID(userId); String url = account.getAvatar(); if( url.startsWith("/") ){ - url = "https://" + Helper.getLiveInstance(getApplicationContext()) + account.getAvatar(); + url = Helper.getLiveInstanceWithProtocol(getApplicationContext()) + account.getAvatar(); } Glide.with(getApplicationContext()) .asBitmap() diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowAccountActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowAccountActivity.java index 52390157e..3c04a56b3 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowAccountActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowAccountActivity.java @@ -412,7 +412,7 @@ public class ShowAccountActivity extends BaseActivity implements OnPostActionInt } String urlHeader = account.getHeader(); if (urlHeader.startsWith("/")) { - urlHeader = "https://" + Helper.getLiveInstance(ShowAccountActivity.this) + account.getHeader(); + urlHeader = Helper.getLiveInstanceWithProtocol(ShowAccountActivity.this) + account.getHeader(); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && !urlHeader.contains("missing.png")) { @@ -451,7 +451,7 @@ public class ShowAccountActivity extends BaseActivity implements OnPostActionInt pp_actionBar = findViewById(R.id.pp_actionBar); String url = account.getAvatar(); if( url.startsWith("/") ){ - url = "https://" + Helper.getLiveInstance(getApplicationContext()) + account.getAvatar(); + url = Helper.getLiveInstanceWithProtocol(getApplicationContext()) + account.getAvatar(); } Glide.with(getApplicationContext()) .asBitmap() diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowConversationActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowConversationActivity.java index e05ec1ac2..a7e81e1fd 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowConversationActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/ShowConversationActivity.java @@ -151,7 +151,7 @@ public class ShowConversationActivity extends BaseActivity implements OnRetrieve Account account = new AccountDAO(getApplicationContext(),db).getAccountByID(userId); String url = account.getAvatar(); if( url.startsWith("/") ){ - url = "https://" + Helper.getLiveInstance(getApplicationContext()) + account.getAvatar(); + url = Helper.getLiveInstanceWithProtocol(getApplicationContext()) + account.getAvatar(); } Glide.with(getApplicationContext()) .asBitmap() diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java index 7e431eec6..9456f2771 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/TootActivity.java @@ -347,7 +347,7 @@ public class TootActivity extends BaseActivity implements OnRetrieveSearcAccount String url = account.getAvatar(); if( url.startsWith("/") ){ - url = "https://" + Helper.getLiveInstance(getApplicationContext()) + account.getAvatar(); + url = Helper.getLiveInstanceWithProtocol(getApplicationContext()) + account.getAvatar(); } Glide.with(getApplicationContext()) .asBitmap() diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/WebviewConnectActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/WebviewConnectActivity.java index 276c147a7..35864e9cd 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/WebviewConnectActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/WebviewConnectActivity.java @@ -119,7 +119,7 @@ public class WebviewConnectActivity extends BaseActivity { @Override public void run() { try { - final String response = new HttpsConnection(WebviewConnectActivity.this).post("https://" + instance + action, 30, parameters, null); + final String response = new HttpsConnection(WebviewConnectActivity.this).post(Helper.instanceWithProtocol(instance) + action, 30, parameters, null); JSONObject resobj; try { resobj = new JSONObject(response); @@ -160,7 +160,7 @@ public class WebviewConnectActivity extends BaseActivity { queryString += "&" + Helper.REDIRECT_URI + "="+ Uri.encode(Helper.REDIRECT_CONTENT_WEB); queryString += "&" + Helper.RESPONSE_TYPE +"=code"; queryString += "&" + Helper.SCOPE +"=" + Helper.OAUTH_SCOPES; - return "https://" + instance + Helper.EP_AUTHORIZE + "?" + queryString; + return Helper.instanceWithProtocol(instance) + Helper.EP_AUTHORIZE + "?" + queryString; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveRemoteDataAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveRemoteDataAsyncTask.java index 23806c04b..fcaf9a6ee 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveRemoteDataAsyncTask.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveRemoteDataAsyncTask.java @@ -19,6 +19,7 @@ import android.os.AsyncTask; import java.lang.ref.WeakReference; import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.Entities.Results; +import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.interfaces.OnRetrieveRemoteAccountInterface; @@ -38,7 +39,7 @@ public class RetrieveRemoteDataAsyncTask extends AsyncTask { public RetrieveRemoteDataAsyncTask(Context context, String username, String instance, OnRetrieveRemoteAccountInterface onRetrieveRemoteAccountInterface){ - this.url = "https://" + instance + "/@" + username; + this.url = Helper.instanceWithProtocol(instance) + "/@" + username; this.listener = onRetrieveRemoteAccountInterface; this.contextReference = new WeakReference<>(context); } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java index 54c9a3ea3..3a26febcc 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java @@ -2030,7 +2030,7 @@ public class API { private String getAbsoluteUrl(String action) { - return "https://" + this.instance + "/api/v1" + action; + return Helper.instanceWithProtocol(this.instance) + "/api/v1" + action; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/HttpsConnection.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/HttpsConnection.java index 44d88f837..1d4455c89 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/HttpsConnection.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/HttpsConnection.java @@ -67,6 +67,7 @@ public class HttpsConnection { private HttpsURLConnection httpsURLConnection; + private HttpURLConnection httpURLConnection; private String since_id, max_id; private Context context; private int CHUNK_SIZE = 4096; @@ -152,8 +153,6 @@ public class HttpsConnection { public String get(String urlConnection) throws IOException, NoSuchAlgorithmException, KeyManagementException, HttpsConnectionException { - HttpsURLConnection httpsURLConnection; - HttpURLConnection httpURLConnection; if( urlConnection.startsWith("https://")) { URL url = new URL(urlConnection); if( proxy !=null ) @@ -207,53 +206,101 @@ public class HttpsConnection { public String post(String urlConnection, int timeout, HashMap paramaters, String token) throws IOException, NoSuchAlgorithmException, KeyManagementException, HttpsConnectionException { - URL url = new URL(urlConnection); - Map params = new LinkedHashMap<>(); - if( paramaters != null) { - Iterator it = paramaters.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry pair = (Map.Entry) it.next(); - params.put(pair.getKey().toString(), pair.getValue()); - it.remove(); + if( urlConnection.startsWith("https://")) { + URL url = new URL(urlConnection); + Map params = new LinkedHashMap<>(); + if (paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } } - } - StringBuilder postData = new StringBuilder(); - for (Map.Entry param : params.entrySet()) { - if (postData.length() != 0) postData.append('&'); - postData.append(param.getKey()); - postData.append('='); - postData.append(String.valueOf(param.getValue())); - } - byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); - 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); - httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); - httpsURLConnection.setRequestMethod("POST"); - if( token != null) - httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + 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); + httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); + httpsURLConnection.setRequestMethod("POST"); + if (token != null) + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); - httpsURLConnection.getOutputStream().write(postDataBytes); - String response; - if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { + httpsURLConnection.getOutputStream().write(postDataBytes); + String response; + if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { + getSinceMaxId(); + response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); + } else { + String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); + int responseCode = httpsURLConnection.getResponseCode(); + httpsURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } getSinceMaxId(); - response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); - }else { - String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); - int responseCode = httpsURLConnection.getResponseCode(); httpsURLConnection.getInputStream().close(); - throw new HttpsConnectionException(responseCode, error); + return response; + }else { + URL url = new URL(urlConnection); + Map params = new LinkedHashMap<>(); + if (paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } + } + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + + if (proxy != null) + httpURLConnection = (HttpURLConnection) url.openConnection(proxy); + else + httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT); + httpURLConnection.setConnectTimeout(timeout * 1000); + httpURLConnection.setDoOutput(true); + httpURLConnection.setRequestMethod("POST"); + if (token != null) + httpURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + + httpURLConnection.getOutputStream().write(postDataBytes); + String response; + if (httpURLConnection.getResponseCode() >= 200 && httpURLConnection.getResponseCode() < 400) { + getSinceMaxId(); + response = new String(ByteStreams.toByteArray(httpURLConnection.getInputStream())); + } else { + String error = new String(ByteStreams.toByteArray(httpURLConnection.getErrorStream())); + int responseCode = httpURLConnection.getResponseCode(); + httpURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } + getSinceMaxId(); + httpURLConnection.getInputStream().close(); + return response; } - getSinceMaxId(); - httpsURLConnection.getInputStream().close(); - return response; } @@ -457,29 +504,56 @@ public class HttpsConnection { public InputStream getPicture(final String downloadUrl) { - try { - URL url = new URL(downloadUrl); - 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(); - // always check HTTP response code first - if (responseCode == HttpURLConnection.HTTP_OK) { - // opens input stream from the HTTP connection - return httpsURLConnection.getInputStream(); - } - httpsURLConnection.getInputStream().close(); - } catch (IOException | NoSuchAlgorithmException | KeyManagementException ignored) {} - if(httpsURLConnection != null) + if( downloadUrl.startsWith("https://")) { try { + URL url = new URL(downloadUrl); + 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(); + // always check HTTP response code first + if (responseCode == HttpURLConnection.HTTP_OK) { + // opens input stream from the HTTP connection + return httpsURLConnection.getInputStream(); + } httpsURLConnection.getInputStream().close(); - } catch (IOException e) { - e.printStackTrace(); + } catch (IOException | NoSuchAlgorithmException | KeyManagementException ignored) { } - return null; + if (httpsURLConnection != null) + try { + httpsURLConnection.getInputStream().close(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + }else { + try { + URL url = new URL(downloadUrl); + if (proxy != null) + httpURLConnection = (HttpURLConnection) url.openConnection(proxy); + else + httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT); + int responseCode = httpURLConnection.getResponseCode(); + // always check HTTP response code first + if (responseCode == HttpURLConnection.HTTP_OK) { + // opens input stream from the HTTP connection + return httpURLConnection.getInputStream(); + } + httpURLConnection.getInputStream().close(); + } catch (IOException ignored) { + } + if (httpURLConnection != null) + try { + httpURLConnection.getInputStream().close(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } } @@ -489,299 +563,588 @@ public class HttpsConnection { * @param listener - OnRetrieveAttachmentInterface: listener to send information about attachment once uploaded. */ public void upload(final InputStream inputStream, final OnRetrieveAttachmentInterface listener) { - - new Thread(new Runnable() { - @Override - public void run() { - try { - - String twoHyphens = "--"; - String boundary = "*****" + Long.toString(System.currentTimeMillis()) + "*****"; - String lineEnd = "\r\n"; - - 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; + + if( Helper.getLiveInstanceWithProtocol(context).startsWith("https://")) { + new Thread(new Runnable() { + @Override + public void run() { try { + + String twoHyphens = "--"; + String boundary = "*****" + Long.toString(System.currentTimeMillis()) + "*****"; + String lineEnd = "\r\n"; + + String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); + final URL url = new URL(Helper.getLiveInstanceWithProtocol(context) + "/api/v1/media"); + ByteArrayOutputStream ous = null; try { - byte[] buffer = new byte[CHUNK_SIZE]; // or other buffer size - ous = new ByteArrayOutputStream(); - int read; - while ((read = inputStream.read(buffer)) != -1) { - ous.write(buffer, 0, read); + try { + byte[] buffer = new byte[CHUNK_SIZE]; // or other buffer size + ous = new ByteArrayOutputStream(); + int read; + while ((read = inputStream.read(buffer)) != -1) { + ous.write(buffer, 0, read); + } + ous.flush(); + } finally { + if (ous != null) + ous.close(); } - ous.flush(); - } finally { - if (ous != null) - ous.close(); + } catch (FileNotFoundException ignored) { + } catch (IOException ignored) { } - } catch (FileNotFoundException ignored) { - } catch (IOException ignored) {} - byte[] pixels = ous.toByteArray(); + byte[] pixels = ous.toByteArray(); - int lengthSent = pixels.length; - lengthSent += 2 * (twoHyphens + boundary + twoHyphens + lineEnd).getBytes().length; - lengthSent += ("Content-Disposition: form-data; name=\"file\";filename=\"picture.png\"" + lineEnd).getBytes().length; - lengthSent += 2 * (lineEnd).getBytes().length; + int lengthSent = pixels.length; + lengthSent += 2 * (twoHyphens + boundary + twoHyphens + lineEnd).getBytes().length; + lengthSent += ("Content-Disposition: form-data; name=\"file\";filename=\"picture.png\"" + lineEnd).getBytes().length; + lengthSent += 2 * (lineEnd).getBytes().length; - if( proxy !=null ) - httpsURLConnection = (HttpsURLConnection)url.openConnection(proxy); - else - httpsURLConnection = (HttpsURLConnection)url.openConnection(); - httpsURLConnection.setFixedLengthStreamingMode(lengthSent); + if (proxy != null) + httpsURLConnection = (HttpsURLConnection) url.openConnection(proxy); + else + httpsURLConnection = (HttpsURLConnection) url.openConnection(); + httpsURLConnection.setFixedLengthStreamingMode(lengthSent); - httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT); - httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); - httpsURLConnection.setDoInput(true); - httpsURLConnection.setDoOutput(true); - httpsURLConnection.setUseCaches(false); + httpsURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT); + httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); + httpsURLConnection.setDoInput(true); + httpsURLConnection.setDoOutput(true); + httpsURLConnection.setUseCaches(false); - httpsURLConnection.setRequestMethod("POST"); - if (token != null) - httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - httpsURLConnection.setRequestProperty("Connection", "Keep-Alive"); - httpsURLConnection.setRequestProperty("Cache-Control", "no-cache"); - httpsURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - httpsURLConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+ boundary); + httpsURLConnection.setRequestMethod("POST"); + if (token != null) + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpsURLConnection.setRequestProperty("Connection", "Keep-Alive"); + httpsURLConnection.setRequestProperty("Cache-Control", "no-cache"); + httpsURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + httpsURLConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); - DataOutputStream request = new DataOutputStream(httpsURLConnection.getOutputStream()); + DataOutputStream request = new DataOutputStream(httpsURLConnection.getOutputStream()); - request.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); - request.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"picture.png\"" + lineEnd); - request.writeBytes(lineEnd); + request.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); + request.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"picture.png\"" + lineEnd); + request.writeBytes(lineEnd); - //request.write(pixels); + //request.write(pixels); - int totalSize = pixels.length; - int bytesTransferred = 0; + int totalSize = pixels.length; + int bytesTransferred = 0; - while (bytesTransferred < totalSize) { - int nextChunkSize = totalSize - bytesTransferred; - if (nextChunkSize > CHUNK_SIZE) { - nextChunkSize = CHUNK_SIZE; + while (bytesTransferred < totalSize) { + int nextChunkSize = totalSize - bytesTransferred; + if (nextChunkSize > CHUNK_SIZE) { + nextChunkSize = CHUNK_SIZE; + } + request.write(pixels, bytesTransferred, nextChunkSize); + bytesTransferred += nextChunkSize; + + + final int progress = 100 * bytesTransferred / totalSize; + ((TootActivity) context).runOnUiThread(new Runnable() { + public void run() { + listener.onUpdateProgress(progress); + } + }); + request.flush(); } - request.write(pixels, bytesTransferred, nextChunkSize); - bytesTransferred += nextChunkSize; + request.writeBytes(lineEnd); + request.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); + request.flush(); + request.close(); - final int progress = 100 * bytesTransferred / totalSize; + if (200 != httpsURLConnection.getResponseCode()) { + String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); + int responseCode = httpsURLConnection.getResponseCode(); + httpsURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } + + InputStream responseStream = new BufferedInputStream(httpsURLConnection.getInputStream()); + + BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(responseStream)); + + String response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); + ((TootActivity) context).runOnUiThread(new Runnable() { + public void run() { + listener.onUpdateProgress(101); + } + }); + + + final Attachment attachment = API.parseAttachmentResponse(new JSONObject(response)); + responseStreamReader.close(); + responseStream.close(); + httpsURLConnection.getInputStream().close(); + + ((TootActivity) context).runOnUiThread(new Runnable() { + public void run() { + listener.onRetrieveAttachment(attachment, null); + } + }); + } catch (Exception e) { + ((TootActivity) context).runOnUiThread(new Runnable() { + public void run() { + listener.onUpdateProgress(101); + } + }); + final Error error = new Error(); + error.setError(e.getMessage()); + if (httpsURLConnection != null) + try { + httpsURLConnection.getInputStream().close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + ((TootActivity) context).runOnUiThread(new Runnable() { + public void run() { + listener.onRetrieveAttachment(null, error); + } + }); + + } + } + }).start(); + }else { + new Thread(new Runnable() { + @Override + public void run() { + try { + + String twoHyphens = "--"; + String boundary = "*****" + Long.toString(System.currentTimeMillis()) + "*****"; + String lineEnd = "\r\n"; + + String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); + final URL url = new URL(Helper.getLiveInstanceWithProtocol(context)+"/api/v1/media"); + ByteArrayOutputStream ous = null; + try { + try { + byte[] buffer = new byte[CHUNK_SIZE]; // or other buffer size + ous = new ByteArrayOutputStream(); + int read; + while ((read = inputStream.read(buffer)) != -1) { + ous.write(buffer, 0, read); + } + ous.flush(); + } finally { + if (ous != null) + ous.close(); + } + } catch (FileNotFoundException ignored) { + } catch (IOException ignored) {} + byte[] pixels = ous.toByteArray(); + + int lengthSent = pixels.length; + lengthSent += 2 * (twoHyphens + boundary + twoHyphens + lineEnd).getBytes().length; + lengthSent += ("Content-Disposition: form-data; name=\"file\";filename=\"picture.png\"" + lineEnd).getBytes().length; + lengthSent += 2 * (lineEnd).getBytes().length; + + if( proxy !=null ) + httpURLConnection = (HttpURLConnection)url.openConnection(proxy); + else + httpURLConnection = (HttpURLConnection)url.openConnection(); + httpURLConnection.setFixedLengthStreamingMode(lengthSent); + + httpURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT); + httpURLConnection.setDoInput(true); + httpURLConnection.setDoOutput(true); + httpURLConnection.setUseCaches(false); + + httpURLConnection.setRequestMethod("POST"); + if (token != null) + httpURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpURLConnection.setRequestProperty("Connection", "Keep-Alive"); + httpURLConnection.setRequestProperty("Cache-Control", "no-cache"); + httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+ boundary); + + + DataOutputStream request = new DataOutputStream(httpURLConnection.getOutputStream()); + + request.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); + request.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"picture.png\"" + lineEnd); + request.writeBytes(lineEnd); + + //request.write(pixels); + + int totalSize = pixels.length; + int bytesTransferred = 0; + + + while (bytesTransferred < totalSize) { + int nextChunkSize = totalSize - bytesTransferred; + if (nextChunkSize > CHUNK_SIZE) { + nextChunkSize = CHUNK_SIZE; + } + request.write(pixels, bytesTransferred, nextChunkSize); + bytesTransferred += nextChunkSize; + + + final int progress = 100 * bytesTransferred / totalSize; + ((TootActivity)context).runOnUiThread(new Runnable() { + public void run() { + listener.onUpdateProgress(progress); + }}); + request.flush(); + } + request.writeBytes(lineEnd); + request.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); + request.flush(); + request.close(); + + + if (200 != httpURLConnection.getResponseCode()) { + String error = new String(ByteStreams.toByteArray(httpURLConnection.getErrorStream())); + int responseCode = httpURLConnection.getResponseCode(); + httpURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } + + InputStream responseStream = new BufferedInputStream(httpURLConnection.getInputStream()); + + BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(responseStream)); + + String response = new String(ByteStreams.toByteArray(httpURLConnection.getInputStream())); ((TootActivity)context).runOnUiThread(new Runnable() { public void run() { - listener.onUpdateProgress(progress); + listener.onUpdateProgress(101); }}); - request.flush(); + + + final Attachment attachment = API.parseAttachmentResponse(new JSONObject(response)); + responseStreamReader.close(); + responseStream.close(); + httpURLConnection.getInputStream().close(); + + ((TootActivity)context).runOnUiThread(new Runnable() { + public void run() { + listener.onRetrieveAttachment(attachment, null); + }}); + }catch (Exception e) { + ((TootActivity)context).runOnUiThread(new Runnable() { + public void run() { + listener.onUpdateProgress(101); + }}); + final Error error = new Error(); + error.setError(e.getMessage()); + if(httpURLConnection != null) + try { + httpURLConnection.getInputStream().close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + ((TootActivity)context).runOnUiThread(new Runnable() { + public void run() { + listener.onRetrieveAttachment(null, error); + }}); + } - request.writeBytes(lineEnd); - request.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); - request.flush(); - request.close(); - - - if (200 != httpsURLConnection.getResponseCode()) { - String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); - int responseCode = httpsURLConnection.getResponseCode(); - httpsURLConnection.getInputStream().close(); - throw new HttpsConnectionException(responseCode, error); - } - - InputStream responseStream = new BufferedInputStream(httpsURLConnection.getInputStream()); - - BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(responseStream)); - - String response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); - ((TootActivity)context).runOnUiThread(new Runnable() { - public void run() { - listener.onUpdateProgress(101); - }}); - - - final Attachment attachment = API.parseAttachmentResponse(new JSONObject(response)); - responseStreamReader.close(); - responseStream.close(); - httpsURLConnection.getInputStream().close(); - - ((TootActivity)context).runOnUiThread(new Runnable() { - public void run() { - listener.onRetrieveAttachment(attachment, null); - }}); - }catch (Exception e) { - ((TootActivity)context).runOnUiThread(new Runnable() { - public void run() { - listener.onUpdateProgress(101); - }}); - final Error error = new Error(); - error.setError(e.getMessage()); - if(httpsURLConnection != null) - try { - httpsURLConnection.getInputStream().close(); - } catch (IOException e1) { - e1.printStackTrace(); - } - ((TootActivity)context).runOnUiThread(new Runnable() { - public void run() { - listener.onRetrieveAttachment(null, error); - }}); - } - } - }).start(); - - + }).start(); + } } public String put(String urlConnection, int timeout, HashMap paramaters, String token) throws IOException, NoSuchAlgorithmException, KeyManagementException, HttpsConnectionException { - URL url = new URL(urlConnection); - Map params = new LinkedHashMap<>(); - if( paramaters != null) { - Iterator it = paramaters.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry pair = (Map.Entry) it.next(); - params.put(pair.getKey().toString(), pair.getValue()); - it.remove(); + if( urlConnection.startsWith("https://")) { + URL url = new URL(urlConnection); + Map params = new LinkedHashMap<>(); + if (paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } } - } - StringBuilder postData = new StringBuilder(); - for (Map.Entry param : params.entrySet()) { - if (postData.length() != 0) postData.append('&'); - postData.append(param.getKey()); - postData.append('='); - postData.append(String.valueOf(param.getValue())); - } - byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); - 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()); - if( token != null) - httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + 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()); + if (token != null) + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); - httpsURLConnection.setRequestMethod("PUT"); - httpsURLConnection.setDoInput(true); - httpsURLConnection.setDoOutput(true); + httpsURLConnection.setRequestMethod("PUT"); + httpsURLConnection.setDoInput(true); + httpsURLConnection.setDoOutput(true); - httpsURLConnection.getOutputStream().write(postDataBytes); - String response; - if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { + httpsURLConnection.getOutputStream().write(postDataBytes); + String response; + if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { + getSinceMaxId(); + response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); + } else { + String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); + int responseCode = httpsURLConnection.getResponseCode(); + httpsURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } getSinceMaxId(); - response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); - }else { - String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); - int responseCode = httpsURLConnection.getResponseCode(); httpsURLConnection.getInputStream().close(); - throw new HttpsConnectionException(responseCode, error); + return response; + }else{ + URL url = new URL(urlConnection); + Map params = new LinkedHashMap<>(); + if (paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } + } + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + + if (proxy != null) + httpURLConnection = (HttpURLConnection) url.openConnection(proxy); + else + httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT); + httpURLConnection.setConnectTimeout(timeout * 1000); + if (token != null) + httpURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + + httpURLConnection.setRequestMethod("PUT"); + httpURLConnection.setDoInput(true); + httpURLConnection.setDoOutput(true); + + httpURLConnection.getOutputStream().write(postDataBytes); + String response; + if (httpURLConnection.getResponseCode() >= 200 && httpURLConnection.getResponseCode() < 400) { + getSinceMaxId(); + response = new String(ByteStreams.toByteArray(httpURLConnection.getInputStream())); + } else { + String error = new String(ByteStreams.toByteArray(httpURLConnection.getErrorStream())); + int responseCode = httpURLConnection.getResponseCode(); + httpURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } + getSinceMaxId(); + httpURLConnection.getInputStream().close(); + return response; } - getSinceMaxId(); - httpsURLConnection.getInputStream().close(); - return response; } public String patch(String urlConnection, int timeout, HashMap paramaters, String token) throws IOException, NoSuchAlgorithmException, KeyManagementException, HttpsConnectionException { - URL url = new URL(urlConnection); - Map params = new LinkedHashMap<>(); - if( paramaters != null) { - Iterator it = paramaters.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry pair = (Map.Entry) it.next(); - params.put(pair.getKey().toString(), pair.getValue()); - it.remove(); + if( urlConnection.startsWith("https://")) { + URL url = new URL(urlConnection); + Map params = new LinkedHashMap<>(); + if (paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } } - } - StringBuilder postData = new StringBuilder(); - for (Map.Entry param : params.entrySet()) { - if (postData.length() != 0) postData.append('&'); - postData.append(param.getKey()); - postData.append('='); - postData.append(String.valueOf(param.getValue())); - } - byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); - 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()); - httpsURLConnection.setRequestMethod("PATCH"); - if( token != null) - httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - httpsURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); - httpsURLConnection.setDoOutput(true); + 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()); + httpsURLConnection.setRequestMethod("PATCH"); + if (token != null) + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpsURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + httpsURLConnection.setDoOutput(true); - httpsURLConnection.getOutputStream().write(postDataBytes); - String response; - if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { + httpsURLConnection.getOutputStream().write(postDataBytes); + String response; + if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { + getSinceMaxId(); + response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); + } else { + String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); + int responseCode = httpsURLConnection.getResponseCode(); + httpsURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } getSinceMaxId(); - response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); - }else { - String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); - int responseCode = httpsURLConnection.getResponseCode(); httpsURLConnection.getInputStream().close(); - throw new HttpsConnectionException(responseCode, error); + return response; + }else { + URL url = new URL(urlConnection); + Map params = new LinkedHashMap<>(); + if (paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } + } + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + + if (proxy != null) + httpURLConnection = (HttpURLConnection) url.openConnection(proxy); + else + httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT); + httpURLConnection.setConnectTimeout(timeout * 1000); + httpURLConnection.setRequestMethod("PATCH"); + if (token != null) + httpURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + httpURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + httpURLConnection.setDoOutput(true); + + httpURLConnection.getOutputStream().write(postDataBytes); + String response; + if (httpURLConnection.getResponseCode() >= 200 && httpURLConnection.getResponseCode() < 400) { + getSinceMaxId(); + response = new String(ByteStreams.toByteArray(httpURLConnection.getInputStream())); + } else { + String error = new String(ByteStreams.toByteArray(httpURLConnection.getErrorStream())); + int responseCode = httpURLConnection.getResponseCode(); + httpURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } + getSinceMaxId(); + httpURLConnection.getInputStream().close(); + return response; } - getSinceMaxId(); - httpsURLConnection.getInputStream().close(); - return response; } public int delete(String urlConnection, int timeout, HashMap paramaters, String token) throws IOException, NoSuchAlgorithmException, KeyManagementException, HttpsConnectionException { - URL url = new URL(urlConnection); - Map params = new LinkedHashMap<>(); - if( paramaters != null) { - Iterator it = paramaters.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry pair = (Map.Entry) it.next(); - params.put(pair.getKey().toString(), pair.getValue()); - it.remove(); + if( urlConnection.startsWith("https://")) { + URL url = new URL(urlConnection); + Map params = new LinkedHashMap<>(); + if (paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } } - } - StringBuilder postData = new StringBuilder(); - for (Map.Entry param : params.entrySet()) { - if (postData.length() != 0) postData.append('&'); - postData.append(param.getKey()); - postData.append('='); - postData.append(String.valueOf(param.getValue())); - } - byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); - 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) - httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - httpsURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - httpsURLConnection.setRequestMethod("DELETE"); - httpsURLConnection.setConnectTimeout(timeout * 1000); - httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + 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) + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpsURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + httpsURLConnection.setRequestMethod("DELETE"); + httpsURLConnection.setConnectTimeout(timeout * 1000); + httpsURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); - httpsURLConnection.getOutputStream().write(postDataBytes); + httpsURLConnection.getOutputStream().write(postDataBytes); - if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { - getSinceMaxId(); - httpsURLConnection.getInputStream().close(); - return httpsURLConnection.getResponseCode(); + if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { + getSinceMaxId(); + httpsURLConnection.getInputStream().close(); + return httpsURLConnection.getResponseCode(); + } else { + String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); + int responseCode = httpsURLConnection.getResponseCode(); + httpsURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } }else { - String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); - int responseCode = httpsURLConnection.getResponseCode(); - httpsURLConnection.getInputStream().close(); - throw new HttpsConnectionException(responseCode, error); + URL url = new URL(urlConnection); + Map params = new LinkedHashMap<>(); + if( paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } + } + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + + if( proxy !=null ) + httpURLConnection = (HttpURLConnection)url.openConnection(proxy); + else + httpURLConnection = (HttpURLConnection)url.openConnection(); + httpURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT); + if( token != null) + httpURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + httpURLConnection.setRequestMethod("DELETE"); + httpURLConnection.setConnectTimeout(timeout * 1000); + httpURLConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + + httpURLConnection.getOutputStream().write(postDataBytes); + + + if (httpURLConnection.getResponseCode() >= 200 && httpURLConnection.getResponseCode() < 400) { + getSinceMaxId(); + httpURLConnection.getInputStream().close(); + return httpURLConnection.getResponseCode(); + }else { + String error = new String(ByteStreams.toByteArray(httpURLConnection.getErrorStream())); + int responseCode = httpURLConnection.getResponseCode(); + httpURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } } } @@ -795,33 +1158,66 @@ public class HttpsConnection { private void getSinceMaxId(){ - if( httpsURLConnection == null) + if( Helper.getLiveInstanceWithProtocol(context) == null) return; - Map> map = httpsURLConnection.getHeaderFields(); - for (Map.Entry> entry : map.entrySet()) { - if( entry.toString().startsWith("Link")){ - Pattern patternMaxId = Pattern.compile("max_id=([0-9]{1,}).*"); - Matcher matcherMaxId = patternMaxId.matcher(entry.toString()); - if (matcherMaxId.find()) { - max_id = matcherMaxId.group(1); - } - if( entry.toString().startsWith("Link")){ - Pattern patternSinceId = Pattern.compile("since_id=([0-9]{1,}).*"); - Matcher matcherSinceId = patternSinceId.matcher(entry.toString()); - if (matcherSinceId.find()) { - since_id = matcherSinceId.group(1); + if( Helper.getLiveInstanceWithProtocol(context).startsWith("https://")) { + if (httpsURLConnection == null) + return; + Map> map = httpsURLConnection.getHeaderFields(); + for (Map.Entry> entry : map.entrySet()) { + if (entry.toString().startsWith("Link")) { + Pattern patternMaxId = Pattern.compile("max_id=([0-9]{1,}).*"); + Matcher matcherMaxId = patternMaxId.matcher(entry.toString()); + if (matcherMaxId.find()) { + max_id = matcherMaxId.group(1); } + if (entry.toString().startsWith("Link")) { + Pattern patternSinceId = Pattern.compile("since_id=([0-9]{1,}).*"); + Matcher matcherSinceId = patternSinceId.matcher(entry.toString()); + if (matcherSinceId.find()) { + since_id = matcherSinceId.group(1); + } + } + } + } + }else { + if (httpURLConnection == null) + return; + Map> map = httpURLConnection.getHeaderFields(); + for (Map.Entry> entry : map.entrySet()) { + if (entry.toString().startsWith("Link")) { + Pattern patternMaxId = Pattern.compile("max_id=([0-9]{1,}).*"); + Matcher matcherMaxId = patternMaxId.matcher(entry.toString()); + if (matcherMaxId.find()) { + max_id = matcherMaxId.group(1); + } + if (entry.toString().startsWith("Link")) { + Pattern patternSinceId = Pattern.compile("since_id=([0-9]{1,}).*"); + Matcher matcherSinceId = patternSinceId.matcher(entry.toString()); + if (matcherSinceId.find()) { + since_id = matcherSinceId.group(1); + } + + } } } } } int getActionCode() { - try { - return httpsURLConnection.getResponseCode(); - } catch (IOException e) { - return -1; + if( Helper.getLiveInstanceWithProtocol(context).startsWith("https://")) { + try { + return httpsURLConnection.getResponseCode(); + } catch (IOException e) { + return -1; + } + }else { + try { + return httpURLConnection.getResponseCode(); + } catch (IOException e) { + return -1; + } } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java index f81d48ae3..ac309e64e 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/helper/Helper.java @@ -895,6 +895,18 @@ public class Helper { return null; } + public static String getLiveInstanceWithProtocol(Context context) { + return instanceWithProtocol(getLiveInstance(context)); + } + + public static String instanceWithProtocol(String instance){ + if( instance == null) + return null; + if( instance.endsWith(".onion")) + return "http://" + instance; + else + return "https://" + instance; + } @@ -958,7 +970,7 @@ public class Helper { item.setIcon(R.drawable.ic_person); String url = account.getAvatar(); if( url.startsWith("/") ){ - url = "https://" + Helper.getLiveInstance(activity) + account.getAvatar(); + url = Helper.getLiveInstanceWithProtocol(activity) + account.getAvatar(); } Glide.with(activity.getApplicationContext()) .asBitmap() @@ -1093,7 +1105,7 @@ public class Helper { */ public static void loadPictureIcon(final Activity activity, String url, final ImageView imageView){ if( url.startsWith("/") ){ - url = "https://" + Helper.getLiveInstance(activity) + url; + url = Helper.getLiveInstanceWithProtocol(activity) + url; } Glide.with(activity.getApplicationContext()) @@ -1169,14 +1181,14 @@ public class Helper { displayedName.setText(account.getDisplay_name()); String url = account.getAvatar(); if( url.startsWith("/") ){ - url = "https://" + Helper.getLiveInstance(activity) + account.getAvatar(); + url = Helper.getLiveInstanceWithProtocol(activity) + account.getAvatar(); } Glide.with(activity.getApplicationContext()) .load(url) .into(profilePicture); String urlHeader = account.getHeader(); if( urlHeader.startsWith("/") ){ - urlHeader = "https://" + Helper.getLiveInstance(activity) + account.getHeader(); + urlHeader = Helper.getLiveInstanceWithProtocol(activity) + account.getHeader(); } if (!urlHeader.contains("missing.png")) { Glide.with(activity.getApplicationContext()) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/services/LiveNotificationService.java b/app/src/main/java/fr/gouv/etalab/mastodon/services/LiveNotificationService.java index 7aadf8adb..26770928d 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/services/LiveNotificationService.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/services/LiveNotificationService.java @@ -156,95 +156,185 @@ public class LiveNotificationService extends Service { private void taks(Account account){ InputStream inputStream = null; HttpsURLConnection httpsURLConnection = null; + HttpURLConnection httpURLConnection = null; BufferedReader reader = null; Helper.EventStreaming lastEvent = null; if( account != null){ isRunning.get(account.getAcct()+account.getInstance()); if(!isRunning.containsKey(account.getAcct()+account.getInstance()) || ! isRunning.get(account.getAcct()+account.getInstance())) { - try { - URL url = new URL("https://" + account.getInstance() + "/api/v1/streaming/user"); - httpsURLConnection = (HttpsURLConnection) url.openConnection(); - httpsURLConnection.setRequestProperty("Content-Type", "application/json"); - httpsURLConnection.setRequestProperty("Authorization", "Bearer " + account.getToken()); - httpsURLConnection.setRequestProperty("Connection", "Keep-Alive"); - httpsURLConnection.setRequestProperty("Keep-Alive", "header"); - httpsURLConnection.setRequestProperty("Connection", "close"); - httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); - httpsURLConnection.setRequestMethod("GET"); - if (httpsURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { - inputStream = new BufferedInputStream(httpsURLConnection.getInputStream()); - reader = new BufferedReader(new InputStreamReader(inputStream)); - String event; - Helper.EventStreaming eventStreaming; - while ((event = reader.readLine()) != null) { - isRunning.put(account.getAcct()+account.getInstance(), true); - if ((lastEvent == Helper.EventStreaming.NONE || lastEvent == null) && !event.startsWith("data: ")) { - switch (event.trim()) { - case "event: update": - lastEvent = Helper.EventStreaming.UPDATE; - break; - case "event: notification": - lastEvent = Helper.EventStreaming.NOTIFICATION; - break; - case "event: delete": - lastEvent = Helper.EventStreaming.DELETE; - break; - default: - lastEvent = Helper.EventStreaming.NONE; - } - } else { - if (!event.startsWith("data: ")) { - lastEvent = Helper.EventStreaming.NONE; - continue; - } - event = event.substring(6); - if (lastEvent == Helper.EventStreaming.UPDATE) { - eventStreaming = Helper.EventStreaming.UPDATE; - } else if (lastEvent == Helper.EventStreaming.NOTIFICATION) { - eventStreaming = Helper.EventStreaming.NOTIFICATION; - } else if (lastEvent == Helper.EventStreaming.DELETE) { - eventStreaming = Helper.EventStreaming.DELETE; - event = "{id:" + event + "}"; + if (Helper.instanceWithProtocol(account.getInstance()).startsWith("https")) { + try { + URL url = new URL("https://" + account.getInstance() + "/api/v1/streaming/user"); + httpsURLConnection = (HttpsURLConnection) url.openConnection(); + httpsURLConnection.setRequestProperty("Content-Type", "application/json"); + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + account.getToken()); + httpsURLConnection.setRequestProperty("Connection", "Keep-Alive"); + httpsURLConnection.setRequestProperty("Keep-Alive", "header"); + httpsURLConnection.setRequestProperty("Connection", "close"); + httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); + httpsURLConnection.setRequestMethod("GET"); + if (httpsURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { + inputStream = new BufferedInputStream(httpsURLConnection.getInputStream()); + reader = new BufferedReader(new InputStreamReader(inputStream)); + String event; + Helper.EventStreaming eventStreaming; + while ((event = reader.readLine()) != null) { + isRunning.put(account.getAcct() + account.getInstance(), true); + if ((lastEvent == Helper.EventStreaming.NONE || lastEvent == null) && !event.startsWith("data: ")) { + switch (event.trim()) { + case "event: update": + lastEvent = Helper.EventStreaming.UPDATE; + break; + case "event: notification": + lastEvent = Helper.EventStreaming.NOTIFICATION; + break; + case "event: delete": + lastEvent = Helper.EventStreaming.DELETE; + break; + default: + lastEvent = Helper.EventStreaming.NONE; + } } else { - eventStreaming = Helper.EventStreaming.UPDATE; - } - lastEvent = Helper.EventStreaming.NONE; - try { - JSONObject eventJson = new JSONObject(event); - onRetrieveStreaming(eventStreaming, account, eventJson); - } catch (JSONException ignored) { ignored.printStackTrace(); + if (!event.startsWith("data: ")) { + lastEvent = Helper.EventStreaming.NONE; + continue; + } + event = event.substring(6); + if (lastEvent == Helper.EventStreaming.UPDATE) { + eventStreaming = Helper.EventStreaming.UPDATE; + } else if (lastEvent == Helper.EventStreaming.NOTIFICATION) { + eventStreaming = Helper.EventStreaming.NOTIFICATION; + } else if (lastEvent == Helper.EventStreaming.DELETE) { + eventStreaming = Helper.EventStreaming.DELETE; + event = "{id:" + event + "}"; + } else { + eventStreaming = Helper.EventStreaming.UPDATE; + } + lastEvent = Helper.EventStreaming.NONE; + try { + JSONObject eventJson = new JSONObject(event); + onRetrieveStreaming(eventStreaming, account, eventJson); + } catch (JSONException ignored) { + ignored.printStackTrace(); + } } } + isRunning.put(account.getAcct() + account.getInstance(), false); } - isRunning.put(account.getAcct() + account.getInstance(), false); - } - } catch (Exception ignored) { - isRunning.put(account.getAcct() + account.getInstance(), false); - ignored.printStackTrace(); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException ignored) { - } - } - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException ignored) { - } - } - if (inputStream != null) { - httpsURLConnection.disconnect(); - } - SystemClock.sleep(5000); - Intent streamingIntent = new Intent(this, LiveNotificationService.class); - streamingIntent.putExtra("userId", account.getId()); - try { - startService(streamingIntent); } catch (Exception ignored) { + isRunning.put(account.getAcct() + account.getInstance(), false); + ignored.printStackTrace(); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ignored) { + } + } + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException ignored) { + } + } + if (inputStream != null) { + httpsURLConnection.disconnect(); + } + SystemClock.sleep(5000); + Intent streamingIntent = new Intent(this, LiveNotificationService.class); + streamingIntent.putExtra("userId", account.getId()); + try { + startService(streamingIntent); + } catch (Exception ignored) { + } + } + }else { + try { + URL url = new URL("https://" + account.getInstance() + "/api/v1/streaming/user"); + httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setRequestProperty("Content-Type", "application/json"); + httpURLConnection.setRequestProperty("Authorization", "Bearer " + account.getToken()); + httpURLConnection.setRequestProperty("Connection", "Keep-Alive"); + httpURLConnection.setRequestProperty("Keep-Alive", "header"); + httpURLConnection.setRequestProperty("Connection", "close"); + httpURLConnection.setRequestMethod("GET"); + if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { + inputStream = new BufferedInputStream(httpURLConnection.getInputStream()); + reader = new BufferedReader(new InputStreamReader(inputStream)); + String event; + Helper.EventStreaming eventStreaming; + while ((event = reader.readLine()) != null) { + isRunning.put(account.getAcct() + account.getInstance(), true); + if ((lastEvent == Helper.EventStreaming.NONE || lastEvent == null) && !event.startsWith("data: ")) { + switch (event.trim()) { + case "event: update": + lastEvent = Helper.EventStreaming.UPDATE; + break; + case "event: notification": + lastEvent = Helper.EventStreaming.NOTIFICATION; + break; + case "event: delete": + lastEvent = Helper.EventStreaming.DELETE; + break; + default: + lastEvent = Helper.EventStreaming.NONE; + } + } else { + if (!event.startsWith("data: ")) { + lastEvent = Helper.EventStreaming.NONE; + continue; + } + event = event.substring(6); + if (lastEvent == Helper.EventStreaming.UPDATE) { + eventStreaming = Helper.EventStreaming.UPDATE; + } else if (lastEvent == Helper.EventStreaming.NOTIFICATION) { + eventStreaming = Helper.EventStreaming.NOTIFICATION; + } else if (lastEvent == Helper.EventStreaming.DELETE) { + eventStreaming = Helper.EventStreaming.DELETE; + event = "{id:" + event + "}"; + } else { + eventStreaming = Helper.EventStreaming.UPDATE; + } + lastEvent = Helper.EventStreaming.NONE; + try { + JSONObject eventJson = new JSONObject(event); + onRetrieveStreaming(eventStreaming, account, eventJson); + } catch (JSONException ignored) { + ignored.printStackTrace(); + } + } + } + isRunning.put(account.getAcct() + account.getInstance(), false); + } + + } catch (Exception ignored) { + isRunning.put(account.getAcct() + account.getInstance(), false); + ignored.printStackTrace(); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ignored) { + } + } + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException ignored) { + } + } + if (inputStream != null) { + httpURLConnection.disconnect(); + } + SystemClock.sleep(5000); + Intent streamingIntent = new Intent(this, LiveNotificationService.class); + streamingIntent.putExtra("userId", account.getId()); + try { + startService(streamingIntent); + } catch (Exception ignored) { + } } } } From 4ec2f1af82f713cebfda3523a41e684acbb97ed9 Mon Sep 17 00:00:00 2001 From: stom79 Date: Wed, 24 Jan 2018 16:27:52 +0100 Subject: [PATCH 30/95] Fixes live notifications and some issues with Tor onion URLs --- .../mastodon/activities/LoginActivity.java | 3 +- .../UpdateAccountInfoAsyncTask.java | 2 +- .../fr/gouv/etalab/mastodon/client/API.java | 2 + .../mastodon/client/HttpsConnection.java | 117 ++++++++++++------ .../services/LiveNotificationService.java | 43 ++++++- 5 files changed, 123 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/LoginActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/LoginActivity.java index 3a6e46a74..23489f88a 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/LoginActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/LoginActivity.java @@ -340,10 +340,11 @@ public class LoginActivity extends BaseActivity { editor.apply(); //Update the account with the token; new UpdateAccountInfoAsyncTask(LoginActivity.this, token, instance).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (JSONException ignored) {} + } catch (JSONException ignored) {ignored.printStackTrace();} } }); }catch (final Exception e) { + e.printStackTrace(); runOnUiThread(new Runnable() { public void run() { connectionButton.setEnabled(true); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/UpdateAccountInfoAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/UpdateAccountInfoAsyncTask.java index 858daf619..fb1899346 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/UpdateAccountInfoAsyncTask.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/UpdateAccountInfoAsyncTask.java @@ -55,7 +55,7 @@ public class UpdateAccountInfoAsyncTask extends AsyncTask { try { //At the state the instance can be encoded instance = URLDecoder.decode(instance, "utf-8"); - } catch (UnsupportedEncodingException ignored) {} + } catch (UnsupportedEncodingException ignored) {ignored.printStackTrace();} SharedPreferences sharedpreferences = this.contextReference.get().getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); if( token == null) { token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java index 3a26febcc..1b004de83 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java @@ -189,8 +189,10 @@ public class API { account = parseAccountResponse(context, new JSONObject(response)); } catch (HttpsConnection.HttpsConnectionException e) { setError(e.getStatusCode(), e); + e.printStackTrace(); }catch (Exception e) { setDefaultError(e); + e.printStackTrace(); } return account; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/HttpsConnection.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/HttpsConnection.java index 1d4455c89..eb5de75e9 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/HttpsConnection.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/HttpsConnection.java @@ -107,47 +107,88 @@ public class HttpsConnection { @SuppressWarnings("ConstantConditions") public String get(String urlConnection, int timeout, HashMap paramaters, String token) throws IOException, NoSuchAlgorithmException, KeyManagementException, HttpsConnectionException { - - Map params = new LinkedHashMap<>(); - if( paramaters != null) { - Iterator it = paramaters.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry pair = (Map.Entry) it.next(); - params.put(pair.getKey().toString(), pair.getValue()); - it.remove(); + if( urlConnection.startsWith("https://")) { + Map params = new LinkedHashMap<>(); + if (paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } } - } - StringBuilder postData = new StringBuilder(); - for (Map.Entry param : params.entrySet()) { - if (postData.length() != 0) postData.append('&'); - postData.append(param.getKey()); - postData.append('='); - postData.append(String.valueOf(param.getValue())); - } - URL url = new URL(urlConnection + "?" + postData); - 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); - httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); - if( token != null) - httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); - httpsURLConnection.setRequestMethod("GET"); - String response; - if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { - response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); - }else { - String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); - int responseCode = httpsURLConnection.getResponseCode(); + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + URL url = new URL(urlConnection + "?" + postData); + 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); + httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); + if (token != null) + httpsURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpsURLConnection.setRequestMethod("GET"); + String response; + if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { + response = new String(ByteStreams.toByteArray(httpsURLConnection.getInputStream())); + } else { + String error = new String(ByteStreams.toByteArray(httpsURLConnection.getErrorStream())); + int responseCode = httpsURLConnection.getResponseCode(); + httpsURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } + getSinceMaxId(); httpsURLConnection.getInputStream().close(); - throw new HttpsConnectionException(responseCode, error); + return response; + }else { + Map params = new LinkedHashMap<>(); + if( paramaters != null) { + Iterator it = paramaters.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry) it.next(); + params.put(pair.getKey().toString(), pair.getValue()); + it.remove(); + } + } + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) { + if (postData.length() != 0) postData.append('&'); + postData.append(param.getKey()); + postData.append('='); + postData.append(String.valueOf(param.getValue())); + } + URL url = new URL(urlConnection + "?" + postData); + if( proxy !=null ) + httpURLConnection = (HttpURLConnection)url.openConnection(proxy); + else + httpURLConnection = (HttpURLConnection)url.openConnection(); + httpURLConnection.setConnectTimeout(timeout * 1000); + httpURLConnection.setRequestProperty("http.keepAlive", "false"); + httpURLConnection.setRequestProperty("User-Agent", Helper.USER_AGENT); + if( token != null) + httpURLConnection.setRequestProperty("Authorization", "Bearer " + token); + httpURLConnection.setRequestMethod("GET"); + String response; + if (httpURLConnection.getResponseCode() >= 200 && httpURLConnection.getResponseCode() < 400) { + response = new String(ByteStreams.toByteArray(httpURLConnection.getInputStream())); + }else { + String error = new String(ByteStreams.toByteArray(httpURLConnection.getErrorStream())); + int responseCode = httpURLConnection.getResponseCode(); + httpURLConnection.getInputStream().close(); + throw new HttpsConnectionException(responseCode, error); + } + getSinceMaxId(); + httpURLConnection.getInputStream().close(); + return response; } - getSinceMaxId(); - httpsURLConnection.getInputStream().close(); - return response; } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/services/LiveNotificationService.java b/app/src/main/java/fr/gouv/etalab/mastodon/services/LiveNotificationService.java index 26770928d..4bc495dfd 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/services/LiveNotificationService.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/services/LiveNotificationService.java @@ -45,7 +45,11 @@ import java.io.BufferedReader; 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.util.ArrayList; import java.util.HashMap; @@ -84,6 +88,8 @@ public class LiveNotificationService extends Service { protected Account account; private boolean stop = false; private static HashMap isRunning = new HashMap<>(); + private Proxy proxy; + public void onCreate() { super.onCreate(); } @@ -95,11 +101,34 @@ public class LiveNotificationService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { + SharedPreferences sharedpreferences = 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); + } + } if( intent == null || intent.getBooleanExtra("stop", false) ) { stop = true; stopSelf(); } - SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); boolean liveNotifications = sharedpreferences.getBoolean(Helper.SET_LIVE_NOTIFICATIONS, true); String userId; @@ -166,7 +195,10 @@ public class LiveNotificationService extends Service { if (Helper.instanceWithProtocol(account.getInstance()).startsWith("https")) { try { URL url = new URL("https://" + account.getInstance() + "/api/v1/streaming/user"); - httpsURLConnection = (HttpsURLConnection) url.openConnection(); + if( proxy != null) + httpsURLConnection = (HttpsURLConnection) url.openConnection(proxy); + else + httpsURLConnection = (HttpsURLConnection) url.openConnection(); httpsURLConnection.setRequestProperty("Content-Type", "application/json"); httpsURLConnection.setRequestProperty("Authorization", "Bearer " + account.getToken()); httpsURLConnection.setRequestProperty("Connection", "Keep-Alive"); @@ -252,8 +284,11 @@ public class LiveNotificationService extends Service { } }else { try { - URL url = new URL("https://" + account.getInstance() + "/api/v1/streaming/user"); - httpURLConnection = (HttpURLConnection) url.openConnection(); + URL url = new URL("http://" + account.getInstance() + "/api/v1/streaming/user"); + if( proxy != null) + httpURLConnection = (HttpURLConnection) url.openConnection(proxy); + else + httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setRequestProperty("Content-Type", "application/json"); httpURLConnection.setRequestProperty("Authorization", "Bearer " + account.getToken()); httpURLConnection.setRequestProperty("Connection", "Keep-Alive"); From c6534ab4c5fa107e0fd35c940a5543a819b29649 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 23:42:10 +0100 Subject: [PATCH 31/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index bb712414c..258957eb4 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -183,8 +183,8 @@ Ցուցադրելու հաշիվ չկա Հետևելու հայտեր չկան Թութեր \n %1$s - Ում ես հետևում \n %1$s - Հետևորդներ \n %1$s + Հետևում եմ \n %1$s + Հետևում են \n %1$s Մեխեր \n %d Թույլատրել Մերժել @@ -215,17 +215,17 @@ and another toot to discover and %d other toots to discover - Delete a notification? - Delete all notifications? - The notification has been deleted! - All notifications have been deleted! + Ջնջե՞լ ծանուցումը + Ջնջե՞լ բոլոր ծանուցումները + Ծանուցումը ջնջված է + Բոլոր ծանուցումները ջնջված են - Following - Followers - Pinned + Հետևում եմ + Հետևորդներ + Մեխած - Unable to get client id! - No Internet connection! + Հաճախորդի id-ն հնարավոր չէ ստանալ + Կապ չկա The account was blocked! The account is no longer blocked! The account was muted! From 14206269d51faa392a7e9e77446f38d9ccc13bdd Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 24 Jan 2018 23:52:01 +0100 Subject: [PATCH 32/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 258957eb4..b1c214eb8 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -226,21 +226,21 @@ Հաճախորդի id-ն հնարավոր չէ ստանալ Կապ չկա - The account was blocked! - The account is no longer blocked! - The account was muted! - The account is no longer muted! - The account was followed! - The account is no longer followed! - The toot was boosted! - The toot is no longer boosted! - The toot was added to your favourites! - The toot was removed from your favourites! - The toot was reported! - The toot was deleted! - The toot was pinned! - The toot was unpinned! - Oops ! An error occurred! + Հաշիվն արգելափակված է + Հաշիվն այլևս արգելափակված չէ + Հաշիվը խլացված է + Հաշիվն այլևս խլացված չէ + Հետևում ես հաշվին + Այլևս չես հետևում հաշվին + Թութը խրախուսվել է + Թութն այլևս չի խրախուսվում + Թութն ավելացվել է քո նախընտրություններին + Թութը հեռացվել է նախընտրություններից + Թութի վերաբերյալ ահազանգ կա + Թութը ջնջվել է + Թութը մեխվել է + Թութն ապամեխվել է + Ուպս! Ինչ-որ բան այն չէ An error occurred! The instance did not return an authorisation code! The instance domain does not seem to be valid! An error occurred while switching between accounts! From d9aa8217d8e4f5d31d069faea6f3e27625fca626 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 25 Jan 2018 00:01:32 +0100 Subject: [PATCH 33/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index b1c214eb8..b1e51db75 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -241,16 +241,16 @@ Թութը մեխվել է Թութն ապամեխվել է Ուպս! Ինչ-որ բան այն չէ - An error occurred! The instance did not return an authorisation code! - The instance domain does not seem to be valid! - An error occurred while switching between accounts! - An error occurred while searching! - Can not log in! - The profile data have been saved! - No action can be taken - The media has been saved! - An error occurred while translating! - Draft saved! + Ինչ որ բան այն չէ! Հանգույցը չվերադարձրեց հաստատման կոդը + Հանգույցի դոմեյնը կարծես անվավեր է + Ինչ-որ սխալ տեղի ունեցավ հաշիվը փոխելու ընթացքում + Փնտրելիս սխալ տեղի ունեցավ + Չես կարող մուտք գործել + Էջի բովանդակությունը պահպանված է + Անհնար է ինչ-րո բան անել + Մեդիան պահպանված է + Թարգմանության ընթացքում սխալ տեղի ունեցավ + Սևագիրը պահված է Are you sure this instance allows this number of characters? Usually, this value is close to 500 characters. Visibility of the toots has been changed for the account %1$s Instance name and screen name cannot be blank! From c6a2d5ab23ec9e8f06e9a28222897edab9dd5822 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 25 Jan 2018 00:11:22 +0100 Subject: [PATCH 34/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index b1e51db75..64de42f93 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -251,22 +251,22 @@ Մեդիան պահպանված է Թարգմանության ընթացքում սխալ տեղի ունեցավ Սևագիրը պահված է - Are you sure this instance allows this number of characters? Usually, this value is close to 500 characters. - Visibility of the toots has been changed for the account %1$s - Instance name and screen name cannot be blank! + Վստա՞հ ես որ սույն հանգույցը թույլատրում է նիշերի նման քանակ։ Սովորաբար առավելագույնը 500 նիշն է։ + Թութերի տեսանելությունը փոխվել է %1$s հաշվի համար + Հանգույցի ու օգտատիրոջ անունները չեն կարող դատարկ լինել - Optimisation of loading - Number of toots per load - Number of accounts per load - Number of notifications per load - Always + Բեռնման լավարկում + Թութերի քանակը մեկ բեռնման համար + Հաշիվների քանակը՝ մեկ բեռնման համար + Ծանուցումների քանակը՝ մեկ բեռնման համար + Միշտ WIFI - Ask - Load the media - Load the pictures - Show more… - Show less… - Sensitive content + Հարցնել + Բեռնել մեդիան + Բեռնել նկարները + Ցույց տալ… + Ցույց չտալ… + Զգայուն բովանդակություն Display previous message in responses Display local timeline Display federated timeline From ad93fd0a4f7cb3c70c8f8f337ab33caaf97b5c97 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 25 Jan 2018 00:21:05 +0100 Subject: [PATCH 35/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 64de42f93..0d9bd0ba2 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -312,36 +312,36 @@ Tabs Menu - Tabs and menu + Ներդիրներ և մենյու - Yandex - No + Յանդեքս + Ոչ - Set LED colour: + Կարգել LED-ի գույնը․ - Blue - Cyan - Magenta - Green - Red - Yellow - White + Կապույտ + Երկնագույն + Մանուշակագույն + Կանաչ + Կարմիր + Դեղին + Սպիտակ - News + Նորություններ Notify for new toots on the home timeline - Display error messages - Follow - Unfollow - Block - Unblock - Mute - No action - Unmute - Request sent - Follows you - Search - First letter in capital for replies + Ցուցադրել սխալների հաղորդումները + Հետևել + Չհետևել + Արգելափակել + Ապաարգելափակել + Խլացնել + Գործողություն չկա + Ապախլացնել + Հայտն ուղարկված է + Հետևում է քեզ + Փնտրել + Առաջին տառը մեծատառով՝ երբ արձագանքում եմ Push notifications From e7ef9ff92cc711654247d199d1cc981c1f44dd0d Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 25 Jan 2018 00:32:13 +0100 Subject: [PATCH 36/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 0d9bd0ba2..5e5a817fa 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -343,7 +343,7 @@ Փնտրել Առաջին տառը մեծատառով՝ երբ արձագանքում եմ - Push notifications + Փուշ ծանուցումներ Please, confirm push notifications that you want to receive. You can enable or disable these notifications later in settings (Notifications tab). From 2f9674b039a63a1f10f342c3c8116ac22d6cebb0 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 25 Jan 2018 00:41:08 +0100 Subject: [PATCH 37/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 5e5a817fa..3103b954c 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -345,18 +345,18 @@ Փուշ ծանուցումներ - Please, confirm push notifications that you want to receive. - You can enable or disable these notifications later in settings (Notifications tab). + Հաստատիր այն փուշ ծանուցումները, որոնք ցանկանում ես ստանալ։ + Հետագայում կարող ես անջատել կամ միացնել այս ծանուցումները կարգավորումներից։ For unread toots in home time-line? - For unread notifications? + Չկարդացած ծանուցումների համա՞ր - Clear cache - There are %1$s of data in cache.\n\nWould you like to delete them? - Mb - Cache was cleared! %1$s were released + Մաքրել քեշը + Քեշում %1$s բովանդակություն կա։\n\nՑանկանում ես ջնջե՞լ + Մբ + Քեշը մաքուր է! %1$s տարածք ազատվեց - Recorded data + Հավաքած բովանդակություն Only basic information from accounts are stored on the device. These data are strictly confidential and can only be used by the application. From 508e9c0e722900a80915968d442fb88131b0ecd2 Mon Sep 17 00:00:00 2001 From: stom79 Date: Thu, 25 Jan 2018 11:11:29 +0100 Subject: [PATCH 38/95] Fixes isssue #259 - link / hashtag highlight color in night mode --- .../etalab/mastodon/client/Entities/Status.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java index 00502e71c..5fa3c5b60 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/Status.java @@ -24,12 +24,14 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; import android.text.Html; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; import android.text.TextPaint; import android.text.style.ClickableSpan; +import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import android.text.style.URLSpan; import android.util.Patterns; @@ -48,6 +50,7 @@ import java.util.Date; import java.util.List; import java.util.regex.Matcher; +import fr.gouv.etalab.mastodon.R; import fr.gouv.etalab.mastodon.activities.HashTagActivity; import fr.gouv.etalab.mastodon.activities.ShowAccountActivity; import fr.gouv.etalab.mastodon.activities.WebviewActivity; @@ -621,7 +624,7 @@ public class Status implements Parcelable{ spannableString.removeSpan(span); List mentions = this.status.getReblog() != null ? this.status.getReblog().getMentions() : this.status.getMentions(); SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE); - + int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); Matcher matcher; if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) @@ -643,10 +646,13 @@ public class Status implements Parcelable{ @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); + ds.setUnderlineText(false); } }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + spannableString.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, theme==Helper.THEME_DARK?R.color.mastodonC2:R.color.mastodonC4)), matchStart, matchEnd, + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } //Deals with mention to make them clickable @@ -671,10 +677,13 @@ public class Status implements Parcelable{ @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); + ds.setUnderlineText(false); } }, startPosition, endPosition, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + spannableString.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, theme==Helper.THEME_DARK?R.color.mastodonC2:R.color.mastodonC4)), startPosition, endPosition, + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } } @@ -697,8 +706,11 @@ public class Status implements Parcelable{ @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); + ds.setUnderlineText(false); } }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + spannableString.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, theme==Helper.THEME_DARK?R.color.mastodonC2:R.color.mastodonC4)), matchStart, matchEnd, + Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } return spannableString; } From ee0768b9a5ae1cee4c41433a8a94b58af24e2915 Mon Sep 17 00:00:00 2001 From: stom79 Date: Thu, 25 Jan 2018 11:24:53 +0100 Subject: [PATCH 39/95] Removes fonts --- .../main/assets/fonts/DroidSans-Regular.ttf | Bin 40664 -> 0 bytes app/src/main/assets/fonts/WorkSans-Regular.ttf | Bin 135828 -> 0 bytes .../drawers/NotificationsListAdapter.java | 2 -- .../mastodon/drawers/StatusListAdapter.java | 4 +--- 4 files changed, 1 insertion(+), 5 deletions(-) delete mode 100755 app/src/main/assets/fonts/DroidSans-Regular.ttf delete mode 100755 app/src/main/assets/fonts/WorkSans-Regular.ttf diff --git a/app/src/main/assets/fonts/DroidSans-Regular.ttf b/app/src/main/assets/fonts/DroidSans-Regular.ttf deleted file mode 100755 index d5009891834ff8c46eb14ec35eedc2a2e20dbc36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40664 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 diff --git a/app/src/main/assets/fonts/WorkSans-Regular.ttf b/app/src/main/assets/fonts/WorkSans-Regular.ttf deleted file mode 100755 index ba11a2de86e30d5a65d95cba43c4a3f0db2961e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135828 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
hwx?Z5*O6SE^=jBJo1S)L>yKwcqh8&XK= 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�B5GL5=n6*vh+B_A>-eQKX)4LhZjm$h@V6` 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

;YYcV5Dr}-&G>Aq4odwY>R^wi$R?&tvxJTJL z?4OKm0(XivqD!oWm4qJAEBbI)ZN2Ch17c8Y5JO_4xIk5 zVyoCDro?tJEoQ_HoVlOHxr=$RAa;q}VvpD>_K6F{esPhwSX?3wh)cy~;&bA1afLXD zRk$G7q5VF)60^k+_I2!{eg%3xVOV2238}yz>SN)U|6V0NFAj;T#Wmtuah>>rI4rIg zH%R*h7eJk&7NbW1R>*F~skmFjt>UOSCT>Ajw z`n`AqW5s3cd*Tn`kK#|_O=wxa#ja()V!vgtuwSz4*vpVze#2g3ud-jW{}O)@e-(ej zX@vh4e;5A{?}&ejcg1_+eer?#Q2dYhNSqZeu?TfE4igp{+#BMfvyIMu^CJ$&`1HKKNsZs6#1}2C`W7{)Ma`mp z#IZ0xu4|WRwe3i&>r{d|Wl+$XEeq3|M`jncPmL_h>(?mBb=^vwZUulI`KDi(o-Asr zXwvm6Df^bC>{AQwQwsL!o1L8AtQ(Xm{Rfv|Mka+t#l@6aVNpq$`m9%;rDo-6R>RFr z%6pj-zqqJez84qS{F@5qcF%1oC@d@rX_AF_y-WB!?~zT8$yvw3_KB(SJ)Xeurm@NK z+3~r_IZsf;5@tPNAx)cSM|O>S-a}QCdjkABmb~2_Z-|0FulMC3MRhx7wr?L%n$Z(0 zv_)2AQ)|K0jAN>^y-|l8=L$;#+__1=niKqC%X2}9u9*^)1~f~0lK!yfWkunuzNMAE zn4?w}Cqs2M2~U7+38?`JdCKrm+X`d`+m<0Rz_x_2K$V_l!a$X%)!gSNr^Xbt>XeoY z@M^^Xh18V-SGHd8@|Fu((P{x+Ef(nAT7haWk-6&Z%A;KYN9iT1f2pa$+Lz%D^cK)Q zH#GvXBihp`O|R=z(kb0a^?T*fc}^akUX@p9#?!)7gwp9`Mk`vF3hhx!P`ae*Un(uA z$1y%OIW;w+B=1>Swysx6qI6;D50pKzta#}K-Algc*2{-i3(rr^PX({>G`M{2TlT6O zQCQiC$__?UJ~Sp_)Q!uB|M(I=7*`{XD-r!BCGq!mw~5KE`bqWUq?*f=Bud?s%tbpz z+-zD2nwCL9Gs}3=jFMb8tHhaAV3?C{K2tN(o9A@%O1gz*=@!&t6<$@M@SqZl`fO01 zrEVUjhMVn5c$pHvxTr$D7Z-uIsXTE(^2B|zeE)qO9E5BhpWQw(JvKTuSKt_#nh%kn z6`<{QU>KO551o`LHf{Crh0WAeivl)#x_MF9=4DNduevFUR2-n-O!dp!N`KhYiUh@e zgike|O65qeo0dcnpx{~ctJ#1a!={&IL-afCMc%VY0;K^|zgObfm5Fr#fbvk9Mfz3x zELnO1O67}guM&B$M33|b@AXh4<)d+In%B&2n%7H=Zkkk|Q|fb0KcOHgQ2DOBge>Qn zj*zxxP&z`Ea|K7p@*eI8Sy?f4Kpz8r4k=pK9>K}*blG8^~QLgfqy z^jDb!6){0SvKnsccW4P7?IeEul%4`##L7N{u;9t%P+*zW14SSuce5V9NjDHalUot) zuks=3Rr)f#TKc5jMn51Nho8Hn!RJPvUg=T@Q9G1FyPe{rPdWVDJqkW|d_Q;JacE~K z%8VP8!86N2pYa0SZ^jL6=rZ<)4E$9NDD!fI;5XxG{~6i-JMh_ee#^`(fu-F^Kj^m( zKXa1yeqTdsmwB-j12r$ zwk*A#R`8Wf6=B+4^s}3OAm%x=U=9vHH*0VNdNBrvb{~CH_^|YOYO%zW5gxgsBNJ~d z@gvkoU$6&1>Z>~!`5L)`i%?*x9}%wf1$(GhzQ&%1To-zo|-#()%+=7g>nqn1Hlr3}SKWyp9`hK#3_ zA-zf&GNLSld?Z*DTgnU7XOa4plO%*o0R+!dHC#@r@Gb=wJf*;br<_a`7pnObmMi%b zmMi%bs`(VE`4pBb`4p=86sq|Ydh(G1PjR6|!c|yUuLwYe^~&U}uwH?y(4xRqh`Vj5 z9)%VKu0o3fSD{6P%Tl42xWte{RD=iNQL-wc%Q=Tam-HkI;yd9F-xch^qu>q^B<3(E z>=>V&oEf9JGZ_CEgsr*pknuf^sgdntGrOndd%}u1G!<*G^~!HyI~T_1<|k*SJ+Y(D zAN%7nA%V=-F#~CX`i~SV;0Z#Tj*idHO>U-OKP5}}0_VoJPr73(xGHZ{pK@Xh+^O%D zrr=Sqqw%TniFu`3@^w~rb*g44y>Adv|OBi=puF%?p@>jBlS=Dlftlw3MZcHV3H$aaFiwG#RuMEo=pn z!Ml}4Lt_VdHQ$^gZbeLYRzN7~vs|vU z;9Y%|tAJSK6P;G+ltsl#rz|d1pG8VI&1yzwXJ>XV?2!2vRapGxyTpMSRPHB(2)k-X zg%UzoQ$xy>kkOg>EsAep$Cwh^++f#{d@waGqnaBO2+R!%dobG+h|RWoni&)$x)2s$2rXGKv)#J5Qj45v$&xmNK(bzf~45lV5L(ny~=*&c~!cW z`!&L=FT2Acy}PqJFi0{FuQ#kYx!;17uHt_6TkY|!@%SdE$Hw>2tRZ}MeDfrc*!Y@9ihkY$N zec_2uDbzHDlxlf8@e=Q#_~JLbd09G`(-S{~t{7V^kl#;0)A(oHwfOF0j*N%xIg`Q3 z`udv&3YKq?NZ$)7=Hp%c1^{tr#NhPr>K{gkfxh{ZuZ(@DRC+q4T9~j7Y zYD|VEgHxL^0)TuPy84|y#(JmDSP$?AoP0RnsWlk^mtpL*&uG1Yz9@y$uhVC^$>G%G zrXsw-aL8~7d7m!y$w0N%_78U@jC2q58wc>!+S89u2~;Vy-ee#k0~#C;Y1t^E08H!f07V&YltB8L&gcVJLsNZj zst4JArsc@@S90Nb0HFaj9yT-`GLBF~NKCN=!lu)Z03h8^IyD)_kw&G6fR9P;Oh+mt z_EgO~Q6LeCvHnbezow}_HNluVkeizC3^JV-qRBZn(wOfIHlYF_p}>Y#suw)Q`T=JU zy>;U)2ygk$5M&c7QDOiF901!H+%Rl7G;DAN18MorP*YoP|7q=5<3PGIXxz9b-x+3V zTif5(qXZ_TB0NHdhnr5bkcPhg(;*=ZPCioa49O!R1?kqG4y2zT{5W|uT0)c2)qk2O z7s#qVgyyAUb5o5-=JqEj-zf=bpS}*DCe47qc^Hkjtf@Yx0Z-!)oe?N*aI)GnID{#w zA;N?mTG78zhMuve(^`7QnNIuAGv0JsN6!S)X+1p?O{ab7nPfWcN6#D+ z5TT&nsT&58jfMgz-$=b9-tm+p6wZu(lZTJq^A*8q-Q#+NY4yZk)D~TB0aNEMS5nViu5#@4Ars|<(q)q&|yOZT6mZ! zVgyg8i72+f*mpkxQ4ThJ;jI>S(4XeJH-Y_=Ra)C{vGBZhvA4dAU{3uT-~ zMFOeiU{%rRW%w_nIQ<&(#t#)34TkDN$g5)Mv!OuA!>L7{h-GjN6VtG+?Y~bLG=_xx zM5ZQwpq?11FIY0lLy1N^x-c4ad4B}+;Caf3AsU9qj809%$QXE;Xc$R=e|P{4U}c&S zfCTPtw2zc07*T>9^}<7zg8a@?2mm3Ds|6PU`h7rC7#~(Zf*ePXI70$~Ukq2oDwoOv zQB)ER3@F_vQ^kR?8mOs~!A@Ur34_6IY^K7fwW=k`r~)cRS#N)Vp&A1$L97NMvn7=4 zGVs=dPo5!MX{dAQYuKo^3}DQ6)~FCPxSM8}#`u+0bT?%!xIzJ8%?|EfJy3AEfJdSa z)_H=_noGe}Pq2*bPP#0P&Ezc4bAMTuX}!r=k#`6*M8t9kJ@cG`(JTed0+in%(M1I4 z#x4<;5xt@S{X~JW5qtv!frnDv_5E~GY(5`h{5#Y~cq0~5Z7fen^=j|b0Tsq3LWUcu zcB+3WVV*!#>*1+#GpZb=bWVs2=!X#n&QkQn)gKey0=CN|Bb;W$X*D@5c(f7Lnt)e> z9b=;#PwgfmM`s(*+F?2aRs&BbJe)jhOlM$#7@jV8WXM{I(}a+2ibI|ribI}WibI}0 zierOk9mOHfdWu7yeu_h$0gBTA&mhGi&jyM^o*{}uo{bd84$lP?hdi4o4ta(t4tYi> zPCY!M6o)(xibI|;ibI}ple5x;<_UUn)*^Vb^wq()MbZ<3t$3L!(hqR!Hbj5;TM6m?$uDC&agK0jPwtV&?@ zc~0MPrzX8?k9*X~rxBs;A@)=^NnL^$+$#;SPE`x%6TUZ1b(tuF@H` zF Date: Thu, 25 Jan 2018 11:26:40 +0100 Subject: [PATCH 40/95] Cleans --- .../gouv/etalab/mastodon/drawers/NotificationsListAdapter.java | 1 - .../java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java | 1 - 2 files changed, 2 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java index 437beea35..7255811b1 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java @@ -17,7 +17,6 @@ package fr.gouv.etalab.mastodon.drawers; import android.content.ClipData; import android.content.ClipboardManager; import android.graphics.Bitmap; -import android.graphics.Typeface; import android.os.CountDownTimer; import android.os.Handler; import android.support.v7.app.AlertDialog; diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index c675b415a..e595914aa 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -18,7 +18,6 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; -import android.graphics.Typeface; import android.os.Handler; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AlertDialog; From c2ccc76d32184e8edb32278102527f978cd2edce Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 25 Jan 2018 12:43:28 +0100 Subject: [PATCH 41/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 3103b954c..e0ec60c20 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -212,8 +212,8 @@ և %d այլ ծանուցումներ - and another toot to discover - and %d other toots to discover + և մեկ այլ թութ + և %d այլ թութ Ջնջե՞լ ծանուցումը Ջնջե՞լ բոլոր ծանուցումները @@ -271,8 +271,8 @@ Display local timeline Display federated timeline Disable GIF avatars - Path: - Save drafts automatically + Հետագիծ․ + Ինքնաշխատ պահել սևագրերը Display counters Add URL of media in toots Manage notifications From 5c2ceb9add69b442ffc1fdb52e4a530842101e9a Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 25 Jan 2018 13:02:12 +0100 Subject: [PATCH 42/95] New translations strings.xml (Armenian) --- app/src/main/res/values-hy/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index e0ec60c20..4cea2574e 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -273,7 +273,7 @@ Disable GIF avatars Հետագիծ․ Ինքնաշխատ պահել սևագրերը - Display counters + Ցուցադրել հաշվիչները Add URL of media in toots Manage notifications Notify when someone follows you From f5f4d4e4038f54fb6ea315d0369ef47c8e8c6986 Mon Sep 17 00:00:00 2001 From: stom79 Date: Thu, 25 Jan 2018 13:47:34 +0100 Subject: [PATCH 43/95] Fixes an issue with text selection --- .../drawers/NotificationsListAdapter.java | 13 ++++++++++++- .../mastodon/drawers/StatusListAdapter.java | 17 +++++++++++++++-- app/src/main/res/layout/drawer_notification.xml | 1 + app/src/main/res/layout/drawer_status.xml | 1 + 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java index 7255811b1..e40c36c4d 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/NotificationsListAdapter.java @@ -251,7 +251,7 @@ public class NotificationsListAdapter extends RecyclerView.Adapter implements On status.makeEmojis(context, NotificationsListAdapter.this); holder.notification_status_content.setText(status.getContentSpan(), TextView.BufferType.SPANNABLE); holder.status_spoiler.setText(status.getContentSpanCW(), TextView.BufferType.SPANNABLE); - + holder.status_spoiler.setMovementMethod(LinkMovementMethod.getInstance()); holder.notification_status_content.setMovementMethod(LinkMovementMethod.getInstance()); boolean displayBoost = sharedpreferences.getBoolean(Helper.SET_DISPLAY_BOOST_COUNT, true); if( displayBoost) { @@ -1015,6 +1015,17 @@ public class NotificationsListAdapter extends RecyclerView.Adapter implements On } + @Override + public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { + super.onViewAttachedToWindow(holder); + final NotificationsListAdapter.ViewHolder viewHolder = (NotificationsListAdapter.ViewHolder) holder; + // Bug workaround for losing text selection ability, see: + // https://code.google.com/p/android/issues/detail?id=208169 + viewHolder.notification_status_content.setEnabled(false); + viewHolder.notification_status_content.setEnabled(true); + viewHolder.status_spoiler.setEnabled(false); + viewHolder.status_spoiler.setEnabled(true); + } class ViewHolder extends RecyclerView.ViewHolder { diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java index e595914aa..c79c06101 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/StatusListAdapter.java @@ -215,6 +215,19 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct } } + @Override + public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { + super.onViewAttachedToWindow(holder); + final ViewHolder viewHolder = (ViewHolder) holder; + // Bug workaround for losing text selection ability, see: + // https://code.google.com/p/android/issues/detail?id=208169 + viewHolder.status_content.setEnabled(false); + viewHolder.status_content.setEnabled(true); + viewHolder.status_spoiler.setEnabled(false); + viewHolder.status_spoiler.setEnabled(true); + } + + class ViewHolder extends RecyclerView.ViewHolder{ LinearLayout status_content_container; LinearLayout status_spoiler_container; @@ -537,9 +550,8 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct holder.status_content.setText(status.getContentSpan(), TextView.BufferType.SPANNABLE); holder.status_spoiler.setText(status.getContentSpanCW(), TextView.BufferType.SPANNABLE); - holder.status_content.setMovementMethod(LinkMovementMethod.getInstance()); - + holder.status_spoiler.setMovementMethod(LinkMovementMethod.getInstance()); //Manages translations final MyTransL myTransL = MyTransL.getInstance(MyTransL.translatorEngine.YANDEX); myTransL.setObfuscation(true); @@ -1497,6 +1509,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct } + @Override public void onRetrieveAccount(Card card) { if( conversationPosition < this.statuses.size() && card != null) diff --git a/app/src/main/res/layout/drawer_notification.xml b/app/src/main/res/layout/drawer_notification.xml index 6fb19b1fa..6a79f1efa 100644 --- a/app/src/main/res/layout/drawer_notification.xml +++ b/app/src/main/res/layout/drawer_notification.xml @@ -94,6 +94,7 @@