From aba36ca6f8263452699502c2c95936bf03cf6621 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Mon, 24 Feb 2020 22:03:00 +0100 Subject: [PATCH 01/16] Compose activity fixes (#1707) * cleanup media keyboard code * fix crash in ComposeActivity when rotating phone while taking photo * fix poll button in ComposeActivity being invisible when disabled --- .../components/compose/ComposeActivity.kt | 58 +++++++------------ .../main/res/values-night/theme_colors.xml | 2 +- 2 files changed, 22 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt index 339bb3c51..a798f4ff0 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt @@ -103,8 +103,6 @@ class ComposeActivity : BaseActivity(), // this only exists when a status is trying to be sent, but uploads are still occurring private var finishingUploadDialog: ProgressDialog? = null - private var currentInputContentInfo: InputContentInfoCompat? = null - private var currentFlags: Int = 0 private var photoUploadUri: Uri? = null @VisibleForTesting var maximumTootCharacters = DEFAULT_CHARACTER_LIMIT @@ -147,6 +145,8 @@ class ComposeActivity : BaseActivity(), subscribeToUpdates(mediaAdapter) setupButtons() + photoUploadUri = savedInstanceState?.getParcelable(PHOTO_UPLOAD_URI_KEY) + /* If the composer is started up as a reply to another post, override the "starting" state * based on what the intent from the reply request passes. */ if (intent != null) { @@ -473,14 +473,7 @@ class ComposeActivity : BaseActivity(), } override fun onSaveInstanceState(outState: Bundle) { - if (currentInputContentInfo != null) { - outState.putParcelable("commitContentInputContentInfo", - currentInputContentInfo!!.unwrap() as Parcelable?) - outState.putInt("commitContentFlags", currentFlags) - } - currentInputContentInfo = null - currentFlags = 0 - outState.putParcelable("photoUploadUri", photoUploadUri) + outState.putParcelable(PHOTO_UPLOAD_URI_KEY, photoUploadUri) super.onSaveInstanceState(outState) } @@ -708,38 +701,25 @@ class ComposeActivity : BaseActivity(), } /** This is for the fancy keyboards which can insert images and stuff. */ - override fun onCommitContent(inputContentInfo: InputContentInfoCompat, flags: Int, opts: Bundle): Boolean { - try { - currentInputContentInfo?.releasePermission() - } catch (e: Exception) { - Log.e(TAG, "InputContentInfoCompat#releasePermission() failed." + e.message) - } finally { - currentInputContentInfo = null - } - + override fun onCommitContent(inputContentInfo: InputContentInfoCompat, flags: Int, opts: Bundle?): Boolean { // Verify the returned content's type is of the correct MIME type val supported = inputContentInfo.description.hasMimeType("image/*") - return supported && onCommitContentInternal(inputContentInfo, flags) - } - - private fun onCommitContentInternal(inputContentInfo: InputContentInfoCompat, flags: Int): Boolean { - if (flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION != 0) { - try { - inputContentInfo.requestPermission() - } catch (e: Exception) { - Log.e(TAG, "InputContentInfoCompat#requestPermission() failed." + e.message) - return false + if(supported) { + val lacksPermission = (flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0 + if(lacksPermission) { + try { + inputContentInfo.requestPermission() + } catch (e: Exception) { + Log.e(TAG, "InputContentInfoCompat#requestPermission() failed." + e.message) + return false + } } + pickMedia(inputContentInfo.contentUri, inputContentInfo) + return true } - // Determine the file size before putting handing it off to be put in the queue. - pickMedia(inputContentInfo.contentUri) - - currentInputContentInfo = inputContentInfo - currentFlags = flags - - return true + return false } private fun sendStatus() { @@ -849,9 +829,12 @@ class ComposeActivity : BaseActivity(), } } - private fun pickMedia(uri: Uri) { + private fun pickMedia(uri: Uri, contentInfoCompat: InputContentInfoCompat? = null) { withLifecycleContext { viewModel.pickMedia(uri).observe { exceptionOrItem -> + + contentInfoCompat?.releasePermission() + exceptionOrItem.asLeftOrNull()?.let { val errorId = when (it) { is VideoSizeException -> { @@ -1026,6 +1009,7 @@ class ComposeActivity : BaseActivity(), private const val PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1 private const val COMPOSE_OPTIONS_EXTRA = "COMPOSE_OPTIONS" + private const val PHOTO_UPLOAD_URI_KEY = "PHOTO_UPLOAD_URI" // Mastodon only counts URLs as this long in terms of status character limits @VisibleForTesting diff --git a/app/src/main/res/values-night/theme_colors.xml b/app/src/main/res/values-night/theme_colors.xml index 11ad69c3c..f30787f65 100644 --- a/app/src/main/res/values-night/theme_colors.xml +++ b/app/src/main/res/values-night/theme_colors.xml @@ -10,7 +10,7 @@ @color/white @color/tusky_grey_90 @color/tusky_grey_70 - @color/tusky_grey_30 + @color/tusky_grey_40 @color/tusky_grey_70 From 80e0c55b67619748ff8d1301f374b4d4c30a44eb Mon Sep 17 00:00:00 2001 From: Levi Bard Date: Tue, 25 Feb 2020 18:33:25 +0100 Subject: [PATCH 02/16] Warn when scheduling a post within 5 minutes (#1698) * Warn when scheduling a post within 5 minutes * Fix NPE when scheduled post time isn't set * Use AlertDialog with option to cancel instead of Toast when a post isn't scheduled far enough in advance * Move schedule validation warning to scheduling bottom sheet * Fix scheduling error display when sending after an initially-valid scheduling time has become invalid --- .../components/compose/ComposeActivity.kt | 19 +++++- .../compose/view/ComposeScheduleView.java | 66 ++++++++++++++----- .../main/res/layout/view_compose_schedule.xml | 21 +++++- app/src/main/res/values/strings.xml | 1 + 4 files changed, 87 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt index a798f4ff0..368819b88 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt @@ -65,6 +65,7 @@ import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener import com.keylesspalace.tusky.components.compose.dialog.makeCaptionDialog import com.keylesspalace.tusky.components.compose.dialog.showAddPollDialog import com.keylesspalace.tusky.components.compose.view.ComposeOptionsListener +import com.keylesspalace.tusky.components.compose.view.ComposeScheduleView import com.keylesspalace.tusky.db.AccountEntity import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.di.ViewModelFactory @@ -695,9 +696,16 @@ class ComposeActivity : BaseActivity(), updateVisibleCharactersLeft() } + private fun verifyScheduledTime(): Boolean { + return composeScheduleView.verifyScheduledTime(composeScheduleView.getDateTime(viewModel.scheduledAt.value)) + } + private fun onSendClicked() { - enableButtons(false) - sendStatus() + if (verifyScheduledTime()) { + sendStatus() + } else { + showScheduleView() + } } /** This is for the fancy keyboards which can insert images and stuff. */ @@ -723,6 +731,7 @@ class ComposeActivity : BaseActivity(), } private fun sendStatus() { + enableButtons(false) val contentText = composeEditField.text.toString() var spoilerText = "" if (viewModel.showContentWarning.value!!) { @@ -974,7 +983,11 @@ class ComposeActivity : BaseActivity(), override fun onTimeSet(view: TimePicker, hourOfDay: Int, minute: Int) { composeScheduleView.onTimeSet(hourOfDay, minute) viewModel.updateScheduledAt(composeScheduleView.time) - scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN + if (verifyScheduledTime()) { + scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN + } else { + showScheduleView() + } } private fun resetSchedule() { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeScheduleView.java b/app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeScheduleView.java index af10b2776..0deb20be7 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeScheduleView.java +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/view/ComposeScheduleView.java @@ -22,6 +22,8 @@ import android.util.AttributeSet; import android.widget.Button; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout; @@ -48,8 +50,10 @@ public class ComposeScheduleView extends ConstraintLayout { private Button resetScheduleButton; private TextView scheduledDateTimeView; + private TextView invalidScheduleWarningView; private Calendar scheduleDateTime; + public static int MINIMUM_SCHEDULED_SECONDS = 330; // Minimum is 5 minutes, pad 30 seconds for posting public ComposeScheduleView(Context context) { super(context); @@ -76,8 +80,10 @@ public class ComposeScheduleView extends ConstraintLayout { resetScheduleButton = findViewById(R.id.resetScheduleButton); scheduledDateTimeView = findViewById(R.id.scheduledDateTime); + invalidScheduleWarningView = findViewById(R.id.invalidScheduleWarning); scheduledDateTimeView.setOnClickListener(v -> openPickDateDialog()); + invalidScheduleWarningView.setText(R.string.warning_scheduling_interval); scheduleDateTime = null; @@ -89,10 +95,13 @@ public class ComposeScheduleView extends ConstraintLayout { private void setScheduledDateTime() { if (scheduleDateTime == null) { scheduledDateTimeView.setText(""); + invalidScheduleWarningView.setVisibility(GONE); } else { + Date scheduled = scheduleDateTime.getTime(); scheduledDateTimeView.setText(String.format("%s %s", - dateFormat.format(scheduleDateTime.getTime()), - timeFormat.format(scheduleDateTime.getTime()))); + dateFormat.format(scheduled), + timeFormat.format(scheduled))); + verifyScheduledTime(scheduled); } } @@ -124,9 +133,7 @@ public class ComposeScheduleView extends ConstraintLayout { .setValidator( DateValidatorPointForward.from(yesterday)) .build(); - if (scheduleDateTime == null) { - scheduleDateTime = Calendar.getInstance(TimeZone.getDefault()); - } + initializeSuggestedTime(); MaterialDatePicker picker = MaterialDatePicker.Builder .datePicker() .setSelection(scheduleDateTime.getTimeInMillis()) @@ -147,6 +154,16 @@ public class ComposeScheduleView extends ConstraintLayout { picker.show(((AppCompatActivity) getContext()).getSupportFragmentManager(), "time_picker"); } + public Date getDateTime(String scheduledAt) { + if (scheduledAt != null) { + try { + return iso8601.parse(scheduledAt); + } catch (ParseException e) { + } + } + return null; + } + public void setDateTime(String scheduledAt) { Date date; try { @@ -154,27 +171,34 @@ public class ComposeScheduleView extends ConstraintLayout { } catch (ParseException e) { return; } - if (scheduleDateTime == null) { - scheduleDateTime = Calendar.getInstance(TimeZone.getDefault()); - } + initializeSuggestedTime(); scheduleDateTime.setTime(date); setScheduledDateTime(); } - private void onDateSet(long selection) { - if (scheduleDateTime == null) { - scheduleDateTime = Calendar.getInstance(TimeZone.getDefault()); + public boolean verifyScheduledTime(@Nullable Date scheduledTime) { + boolean valid; + if (scheduledTime != null) { + Calendar minimumScheduledTime = getCalendar(); + minimumScheduledTime.add(Calendar.SECOND, MINIMUM_SCHEDULED_SECONDS); + valid = scheduledTime.after(minimumScheduledTime.getTime()); + } else { + valid = true; } - Calendar newDate = Calendar.getInstance(TimeZone.getDefault()); + invalidScheduleWarningView.setVisibility(valid ? GONE : VISIBLE); + return valid; + } + + private void onDateSet(long selection) { + initializeSuggestedTime(); + Calendar newDate = getCalendar(); newDate.setTimeInMillis(selection); scheduleDateTime.set(newDate.get(Calendar.YEAR), newDate.get(Calendar.MONTH), newDate.get(Calendar.DATE)); openPickTimeDialog(); } public void onTimeSet(int hourOfDay, int minute) { - if (scheduleDateTime == null) { - scheduleDateTime = Calendar.getInstance(TimeZone.getDefault()); - } + initializeSuggestedTime(); scheduleDateTime.set(Calendar.HOUR_OF_DAY, hourOfDay); scheduleDateTime.set(Calendar.MINUTE, minute); setScheduledDateTime(); @@ -186,4 +210,16 @@ public class ComposeScheduleView extends ConstraintLayout { } return iso8601.format(scheduleDateTime.getTime()); } + + @NonNull + public static Calendar getCalendar() { + return Calendar.getInstance(TimeZone.getDefault()); + } + + private void initializeSuggestedTime() { + if (scheduleDateTime == null) { + scheduleDateTime = getCalendar(); + scheduleDateTime.add(Calendar.MINUTE, 15); + } + } } diff --git a/app/src/main/res/layout/view_compose_schedule.xml b/app/src/main/res/layout/view_compose_schedule.xml index 98ef4f166..b07270f6a 100644 --- a/app/src/main/res/layout/view_compose_schedule.xml +++ b/app/src/main/res/layout/view_compose_schedule.xml @@ -10,7 +10,7 @@ android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:text="@string/action_reset_schedule" - app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintBottom_toTopOf="@id/invalidScheduleWarning" app:layout_constraintStart_toStartOf="parent" /> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7311b17b5..f6b49e195 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -547,5 +547,6 @@ You don\'t have any drafts. You don\'t have any scheduled statuses. + Mastodon has a minimum scheduling interval of 5 minutes. From 921aae5012052322b7672f103d43bb0a1ff8239a Mon Sep 17 00:00:00 2001 From: Anonymous Date: Sat, 22 Feb 2020 16:58:48 +0000 Subject: [PATCH 03/16] Translated using Weblate (Slovak) Currently translated at 28.4% (116 of 409 strings) Translation: Tusky/Tusky Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/sk/ Translated using Weblate (Swedish) Currently translated at 100.0% (409 of 409 strings) Translation: Tusky/Tusky Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/sv/ Translated using Weblate (Swedish) Currently translated at 100.0% (409 of 409 strings) Translation: Tusky/Tusky Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/sv/ Added translation using Weblate (Luxembourgish) Added translation using Weblate (French (Belgium)) Added translation using Weblate (English (United States)) Added translation using Weblate (English (Australia)) --- app/src/main/res/values-en-rAU/strings.xml | 2 ++ app/src/main/res/values-en-rUS/strings.xml | 2 ++ app/src/main/res/values-fr-rBE/strings.xml | 2 ++ app/src/main/res/values-lb/strings.xml | 2 ++ app/src/main/res/values-sk/strings.xml | 15 +++++++++++++++ app/src/main/res/values-sv/strings.xml | 8 ++++---- 6 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/values-en-rAU/strings.xml create mode 100644 app/src/main/res/values-en-rUS/strings.xml create mode 100644 app/src/main/res/values-fr-rBE/strings.xml create mode 100644 app/src/main/res/values-lb/strings.xml diff --git a/app/src/main/res/values-en-rAU/strings.xml b/app/src/main/res/values-en-rAU/strings.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/app/src/main/res/values-en-rAU/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values-fr-rBE/strings.xml b/app/src/main/res/values-fr-rBE/strings.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/app/src/main/res/values-fr-rBE/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values-lb/strings.xml b/app/src/main/res/values-lb/strings.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/app/src/main/res/values-lb/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 8c42b4b47..e5758c727 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -112,4 +112,19 @@ Uložiť koncept\? Odosielanie tootov Odosielanie bolo zrušené + Vyhľadávanie… + Neskôr + Reštartovať + Robot + CC-BY 4.0 + CC-BY-SA 4.0 + + Metadáta profilu + pridať dáta + Obsah + + %1$s + %1$s a %2$s + Žiadny popis + Verejný diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index df30ececf..129ece033 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -395,8 +395,8 @@ Notifieringar när omröstningar har avslutats - En undersökning där du har röstat är avslutad - En undersökning du skapat har avslutats + En omröstning där du har röstat är avslutad + En omröstning som du har skapat har avslutats %d dag @@ -419,7 +419,7 @@ Animera profil gifar - Undersökning med valen: %1$s, %2$s, %3$s, %4$s; %5$s + Omröstning med valen: %1$s, %2$s, %3$s, %4$s; %5$s Dolda domäner Dolda domäner @@ -448,7 +448,7 @@ Konton Sökning misslyckades - Lägg till omröstning + Skapa en omröstning Omröstning 5 minuter 30 minuter From a4d9116bb8bbd4c2b2eaf3c3db831b23114230db Mon Sep 17 00:00:00 2001 From: ButterflyOfFire Date: Sat, 22 Feb 2020 16:58:48 +0000 Subject: [PATCH 04/16] Translated using Weblate (Occitan) Currently translated at 100.0% (409 of 409 strings) Translation: Tusky/Tusky Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/oc/ Translated using Weblate (Kabyle) Currently translated at 51.8% (212 of 409 strings) Translation: Tusky/Tusky Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/kab/ --- app/src/main/res/values-kab/strings.xml | 23 +++++++++++++++++++++++ app/src/main/res/values-oc/strings.xml | 4 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml index 0a7c51e70..09780b592 100644 --- a/app/src/main/res/values-kab/strings.xml +++ b/app/src/main/res/values-kab/strings.xml @@ -236,4 +236,27 @@ Nadi γef medden i teṭafareḍ Imeḍfaṛen + Iseγwan + Tibdarin + Tibdarin + Iseγwan + Yettwaceyyaɛ! + Yettwaceyyaɛ! + Ula d yiwen n ugmuḍ + + I yimeḍfaṛen kan + + Teγzi n weḍṛis + + Yettwamdemmar s Tusky + Asmel Web n usenfaṛ: +\n https://tusky.app + %dasr + %dtas + %dtasn + + Sekles amzun d arewway\? + Ticki + Aṛubut + Yettwarna γer ticṛad diff --git a/app/src/main/res/values-oc/strings.xml b/app/src/main/res/values-oc/strings.xml index 3fe616ecb..31e2a0406 100644 --- a/app/src/main/res/values-oc/strings.xml +++ b/app/src/main/res/values-oc/strings.xml @@ -337,8 +337,8 @@ CC-BY-SA 4.0 - <b>%1$s</b> Favorit - <b>3%1$s</b>4 Favorits + %1$s Favorit + %1$s Favorits From 091d59680b6eb0005c598dc63d29fa758357a2b3 Mon Sep 17 00:00:00 2001 From: Daniele Lira Mereb Date: Sat, 22 Feb 2020 16:58:48 +0000 Subject: [PATCH 05/16] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (409 of 409 strings) Translation: Tusky/Tusky Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/pt_BR/ --- app/src/main/res/values-pt-rBR/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 6c8de2065..41370ef78 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -32,7 +32,7 @@ Favoritos Usuários silenciados Usuários bloqueados - Solicitações de seguidor + Seguidores pendentes Editar seu perfil Rascunhos Licenças @@ -76,7 +76,7 @@ Favoritos Usuários silenciados Usuários bloqueados - Solicitações de seguidor + Seguidores pendentes Mídia Abrir no navegador Adicionar mídia From ff0529217b3a1d7db3b1e487fabc060fd06a8f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isak=20Holmstr=C3=B6m?= Date: Sat, 22 Feb 2020 16:58:48 +0000 Subject: [PATCH 06/16] Translated using Weblate (Swedish) Currently translated at 100.0% (409 of 409 strings) Translation: Tusky/Tusky Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/sv/ --- app/src/main/res/values-sv/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 129ece033..f4b14c504 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -42,7 +42,7 @@ %s knuffade Känsligt innehåll Dold media - Klicka för att se + Tryck för att visa Visa mer Visa mindre Expandera From 563d920f63cb6ae8a14ba44526bc77612e1e6951 Mon Sep 17 00:00:00 2001 From: hg Date: Sat, 22 Feb 2020 16:58:48 +0000 Subject: [PATCH 07/16] Translated using Weblate (Swedish) Currently translated at 100.0% (409 of 409 strings) Translation: Tusky/Tusky Translate-URL: https://weblate.tusky.app/projects/tusky/tusky/sv/ --- app/src/main/res/values-sv/strings.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index f4b14c504..4bad9f70f 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -4,7 +4,7 @@ Ett nätverksfel inträffade! Kontrollera att du är ansluten till internet och försök igen! Det här kan inte vara tomt. Ogiltig domän angiven - Misslyckades med att autentisera med den instansen. + Kunde inte med att autentisera med den instansen. Det gick inte att hitta en webbläsare. Ett oidentifierat behörighetsfel inträffade. Ingen behörighet. @@ -152,7 +152,7 @@ Laddar upp… Ladda ned Återkalla följningsförfrågan? - Avfölja detta konto? + Sluta följ detta konto\? Radera denna toot? Offentlig: Skicka till offentliga tidslinjer Olistad: Visa inte i offentliga tidslinjer @@ -170,7 +170,7 @@ mina inlägg är knuffade mina inlägg är favoriserade Utseende - Applikationstema + Tema Tidslinjer Filter Mörkt @@ -438,7 +438,7 @@ Vidarebefordra till %s Misslyckades att anmäla Misslyckades att hämta status - Anmälan kommer att skickas till din serveradminstratör. Du kan beskriva varför du anmäler kontot nedan: + Anmälan kommer att skickas till din servermoderator. Du kan beskriva varför du anmäler kontot nedan: Kontot är från en annan server. Skicka en anonym kopia av anmälan dit också\? Visa notifikationsfilter @@ -463,7 +463,7 @@ Redigera Schemalagda toots - Redigera + Ändra Schemalagda toots Schemalägg toot Återställ From c4a8924490dcf7d716f6770a58c80ee12006e0be Mon Sep 17 00:00:00 2001 From: Vegard Skjefstad Date: Tue, 18 Feb 2020 05:41:36 +0000 Subject: [PATCH 08/16] =?UTF-8?q?Translated=20using=20Weblate=20(Norwegian?= =?UTF-8?q?=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (8 of 8 strings) Translation: Tusky/Tusky-app Translate-URL: https://weblate.tusky.app/projects/tusky/tusky-app/nb_NO/ --- fastlane/metadata/android/nb_NO/changelogs/70.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 fastlane/metadata/android/nb_NO/changelogs/70.txt diff --git a/fastlane/metadata/android/nb_NO/changelogs/70.txt b/fastlane/metadata/android/nb_NO/changelogs/70.txt new file mode 100644 index 000000000..d19466d64 --- /dev/null +++ b/fastlane/metadata/android/nb_NO/changelogs/70.txt @@ -0,0 +1,8 @@ +Tusky v10.0 + +- Du kan nå legge til statuser som bokmerker, og se bokmerkene i Tusky. +- Du kan nå planlegge et toot for publisering i framtiden. +- Du kan nå legge til lister på hovedskjermen. +- Du kan nå publisere lydvedlegg med Tusky. + +I tillegg er det mange andre mindre forbedringer og feilrettinger! From e045693ebdbe4c761cf58bd9b08f5d13e0c4b007 Mon Sep 17 00:00:00 2001 From: Daniele Lira Mereb Date: Tue, 25 Feb 2020 02:21:58 +0000 Subject: [PATCH 09/16] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (8 of 8 strings) Translation: Tusky/Tusky-app Translate-URL: https://weblate.tusky.app/projects/tusky/tusky-app/pt_BR/ --- fastlane/metadata/android/pt_BR/changelogs/70.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 fastlane/metadata/android/pt_BR/changelogs/70.txt diff --git a/fastlane/metadata/android/pt_BR/changelogs/70.txt b/fastlane/metadata/android/pt_BR/changelogs/70.txt new file mode 100644 index 000000000..90d2e38bb --- /dev/null +++ b/fastlane/metadata/android/pt_BR/changelogs/70.txt @@ -0,0 +1,8 @@ +Tusky v10.0 + +- Pra quem não aguenta mais perder toots no meio dos favoritos, o Salvos chegou! +- Agora dá para agendar toots, porém é necessário agendá-los para ao menos 5 minutos depois, certo? +- Utilidade pública: Finalmente poderemos adicionar listas na barrinha do Tusky! +- Filosofou no áudio de uma conversa e quer compartilhar com o fediverso? Você já pode anexar áudios nos toots, só não se esqueça de descrevê-los! + +E muitas outras pequenas melhorias e correções de bugs! From 82f5fe49b15158442be10115514c722a64620f89 Mon Sep 17 00:00:00 2001 From: Conny Duck Date: Tue, 25 Feb 2020 18:47:53 +0100 Subject: [PATCH 10/16] cleanup empty translations, add german translation --- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-en-rAU/strings.xml | 2 -- app/src/main/res/values-en-rUS/strings.xml | 2 -- app/src/main/res/values-fr-rBE/strings.xml | 2 -- app/src/main/res/values-lb/strings.xml | 2 -- 5 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 app/src/main/res/values-en-rAU/strings.xml delete mode 100644 app/src/main/res/values-en-rUS/strings.xml delete mode 100644 app/src/main/res/values-fr-rBE/strings.xml delete mode 100644 app/src/main/res/values-lb/strings.xml diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index ba7185156..55484c431 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -469,5 +469,6 @@ Du hast keine Entwürfe. Du hast keine geplanten Beiträge. + Das Datum des geplanten Toots muss mindestens 5 Minuten in der Zukunft liegen. diff --git a/app/src/main/res/values-en-rAU/strings.xml b/app/src/main/res/values-en-rAU/strings.xml deleted file mode 100644 index a6b3daec9..000000000 --- a/app/src/main/res/values-en-rAU/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml deleted file mode 100644 index a6b3daec9..000000000 --- a/app/src/main/res/values-en-rUS/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/values-fr-rBE/strings.xml b/app/src/main/res/values-fr-rBE/strings.xml deleted file mode 100644 index a6b3daec9..000000000 --- a/app/src/main/res/values-fr-rBE/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/values-lb/strings.xml b/app/src/main/res/values-lb/strings.xml deleted file mode 100644 index a6b3daec9..000000000 --- a/app/src/main/res/values-lb/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file From 218046fd277ccf692ec47d5e24677f52232d1f34 Mon Sep 17 00:00:00 2001 From: Conny Duck Date: Tue, 25 Feb 2020 19:00:21 +0100 Subject: [PATCH 11/16] Release 70 / 10.0 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b3a850a8f..59f6a5796 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,8 +20,8 @@ android { applicationId APP_ID minSdkVersion 21 targetSdkVersion 29 - versionCode 69 - versionName "10.0 beta 1" + versionCode 70 + versionName "10.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true From 398ee66084c693db791cada1e137127c8f7d021e Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Tue, 25 Feb 2020 19:49:15 +0100 Subject: [PATCH 12/16] simplify DI & test setup, convert TuskyApplication to Kotlin (#1675) * simplify DI & test setup, convert TuskyApplication to Kotlin * try to fix tests on bitrise * remove conscrypt-openjdk-uber test dependency again --- .../com/keylesspalace/tusky/BaseActivity.java | 2 +- .../keylesspalace/tusky/TuskyApplication.java | 158 ------------------ .../keylesspalace/tusky/TuskyApplication.kt | 85 ++++++++++ .../keylesspalace/tusky/db/AccountManager.kt | 17 +- .../com/keylesspalace/tusky/di/AppModule.kt | 21 ++- .../keylesspalace/tusky/di/NetworkModule.kt | 46 ++--- .../tusky/ComposeActivityTest.kt | 2 +- .../tusky/FakeTuskyApplication.kt | 26 --- .../com/keylesspalace/tusky/FilterTest.kt | 2 +- .../keylesspalace/tusky/TuskyApplication.kt | 51 ++++++ .../com/keylesspalace/tusky/di/AppInjector.kt | 2 - .../keylesspalace/tusky/util/RickRollTest.kt | 3 +- .../tusky/util/SmartLengthInputFilterTest.kt | 3 +- 13 files changed, 176 insertions(+), 242 deletions(-) delete mode 100644 app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java create mode 100644 app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt delete mode 100644 app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt create mode 100644 app/src/test/java/com/keylesspalace/tusky/TuskyApplication.kt delete mode 100644 app/src/test/java/com/keylesspalace/tusky/di/AppInjector.kt diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java index d1718bea7..363872684 100644 --- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java @@ -92,7 +92,7 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab @Override protected void attachBaseContext(Context base) { - super.attachBaseContext(TuskyApplication.localeManager.setLocale(base)); + super.attachBaseContext(TuskyApplication.getLocaleManager().setLocale(base)); } protected boolean requiresLogin() { diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java deleted file mode 100644 index 6bf824613..000000000 --- a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright 2017 Andrew Dawson - * - * This file is a part of Tusky. - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 3 of the - * License, or (at your option) any later version. - * - * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. - * - * You should have received a copy of the GNU General Public License along with Tusky; if not, - * see . */ - -package com.keylesspalace.tusky; - -import android.app.Application; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.res.Configuration; - -import androidx.emoji.text.EmojiCompat; -import androidx.preference.PreferenceManager; -import androidx.room.Room; - -import com.evernote.android.job.JobManager; -import com.keylesspalace.tusky.db.AccountManager; -import com.keylesspalace.tusky.db.AppDatabase; -import com.keylesspalace.tusky.di.AppInjector; -import com.keylesspalace.tusky.util.EmojiCompatFont; -import com.keylesspalace.tusky.util.LocaleManager; -import com.keylesspalace.tusky.util.NotificationPullJobCreator; -import com.keylesspalace.tusky.util.ThemeUtils; -import com.uber.autodispose.AutoDisposePlugins; - -import org.conscrypt.Conscrypt; - -import java.security.Security; - -import javax.inject.Inject; - -import dagger.android.AndroidInjector; -import dagger.android.DispatchingAndroidInjector; -import dagger.android.HasAndroidInjector; - -public class TuskyApplication extends Application implements HasAndroidInjector { - @Inject - DispatchingAndroidInjector androidInjector; - - @Inject - NotificationPullJobCreator notificationPullJobCreator; - - private AppDatabase appDatabase; - private AccountManager accountManager; - - private ServiceLocator serviceLocator; - - public static LocaleManager localeManager; - - @Override - public void onCreate() { - super.onCreate(); - - initSecurityProvider(); - - appDatabase = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tuskyDB") - .allowMainThreadQueries() - .addMigrations(AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5, - AppDatabase.MIGRATION_5_6, AppDatabase.MIGRATION_6_7, AppDatabase.MIGRATION_7_8, - AppDatabase.MIGRATION_8_9, AppDatabase.MIGRATION_9_10, AppDatabase.MIGRATION_10_11, - AppDatabase.MIGRATION_11_12, AppDatabase.MIGRATION_12_13, AppDatabase.MIGRATION_10_13, - AppDatabase.MIGRATION_13_14, AppDatabase.MIGRATION_14_15, AppDatabase.MIGRATION_15_16, - AppDatabase.MIGRATION_16_17, AppDatabase.MIGRATION_17_18, AppDatabase.MIGRATION_18_19, - AppDatabase.MIGRATION_19_20, AppDatabase.MIGRATION_20_21) - .build(); - accountManager = new AccountManager(appDatabase); - serviceLocator = new ServiceLocator() { - @Override - public T get(Class clazz) { - if (clazz.equals(AccountManager.class)) { - //noinspection unchecked - return (T) accountManager; - } else if (clazz.equals(AppDatabase.class)) { - //noinspection unchecked - return (T) appDatabase; - } else { - throw new IllegalArgumentException("Unknown service " + clazz); - } - } - }; - - AutoDisposePlugins.setHideProxies(false); - - initAppInjector(); - initEmojiCompat(); - initNightMode(); - - JobManager.create(this).addJobCreator(notificationPullJobCreator); - - } - - protected void initSecurityProvider() { - Security.insertProviderAt(Conscrypt.newProvider(), 1); - } - - @Override - protected void attachBaseContext(Context base) { - localeManager = new LocaleManager(base); - super.attachBaseContext(localeManager.setLocale(base)); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - localeManager.setLocale(this); - } - - /** - * This method will load the EmojiCompat font which has been selected. - * If this font does not work or if the user hasn't selected one (yet), it will use a - * fallback solution instead which won't make any visible difference to using no EmojiCompat at all. - */ - private void initEmojiCompat() { - int emojiSelection = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()) - .getInt(EmojiPreference.FONT_PREFERENCE, 0); - EmojiCompatFont font = EmojiCompatFont.byId(emojiSelection); - // FileEmojiCompat will handle any non-existing font and provide a fallback solution. - EmojiCompat.Config config = font.getConfig(getApplicationContext()) - // The user probably wants to get a consistent experience - .setReplaceAll(true); - EmojiCompat.init(config); - } - - protected void initAppInjector() { - AppInjector.INSTANCE.init(this); - } - - protected void initNightMode() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - String theme = preferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT); - ThemeUtils.setAppNightMode(theme); - } - - public ServiceLocator getServiceLocator() { - return serviceLocator; - } - - @Override - public AndroidInjector androidInjector() { - return androidInjector; - } - - public interface ServiceLocator { - T get(Class clazz); - } -} diff --git a/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt new file mode 100644 index 000000000..a86745a49 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/TuskyApplication.kt @@ -0,0 +1,85 @@ +/* Copyright 2020 Tusky Contributors + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tusky; if not, + * see . */ + +package com.keylesspalace.tusky + +import android.app.Application +import android.content.Context +import android.content.res.Configuration +import androidx.emoji.text.EmojiCompat +import androidx.preference.PreferenceManager +import com.evernote.android.job.JobManager +import com.keylesspalace.tusky.di.AppInjector +import com.keylesspalace.tusky.util.EmojiCompatFont +import com.keylesspalace.tusky.util.LocaleManager +import com.keylesspalace.tusky.util.NotificationPullJobCreator +import com.keylesspalace.tusky.util.ThemeUtils +import com.uber.autodispose.AutoDisposePlugins +import dagger.android.DispatchingAndroidInjector +import dagger.android.HasAndroidInjector +import org.conscrypt.Conscrypt +import java.security.Security +import javax.inject.Inject + +class TuskyApplication : Application(), HasAndroidInjector { + + @Inject + lateinit var androidInjector: DispatchingAndroidInjector + @Inject + lateinit var notificationPullJobCreator: NotificationPullJobCreator + + override fun onCreate() { + + super.onCreate() + + Security.insertProviderAt(Conscrypt.newProvider(), 1) + + AutoDisposePlugins.setHideProxies(false) // a small performance optimization + + AppInjector.init(this) + + val preferences = PreferenceManager.getDefaultSharedPreferences(this) + + // init the custom emoji fonts + val emojiSelection = preferences.getInt(EmojiPreference.FONT_PREFERENCE, 0) + val emojiConfig = EmojiCompatFont.byId(emojiSelection) + .getConfig(this) + .setReplaceAll(true) + EmojiCompat.init(emojiConfig) + + // init night mode + val theme = preferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT) + ThemeUtils.setAppNightMode(theme) + + JobManager.create(this).addJobCreator(notificationPullJobCreator) + } + + override fun attachBaseContext(base: Context) { + localeManager = LocaleManager(base) + super.attachBaseContext(localeManager.setLocale(base)) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + localeManager.setLocale(this) + } + + override fun androidInjector() = androidInjector + + companion object { + @JvmStatic + lateinit var localeManager: LocaleManager + } +} \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt index b02d8c75a..5293bd03a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt +++ b/app/src/main/java/com/keylesspalace/tusky/db/AccountManager.kt @@ -18,6 +18,10 @@ package com.keylesspalace.tusky.db import android.util.Log import com.keylesspalace.tusky.entity.Account import com.keylesspalace.tusky.entity.Status +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.Comparator /** * This class caches the account database and handles all account related operations @@ -26,7 +30,8 @@ import com.keylesspalace.tusky.entity.Status private const val TAG = "AccountManager" -class AccountManager(db: AppDatabase) { +@Singleton +class AccountManager @Inject constructor(db: AppDatabase) { @Volatile var activeAccount: AccountEntity? = null @@ -60,7 +65,7 @@ class AccountManager(db: AppDatabase) { val maxAccountId = accounts.maxBy { it.id }?.id ?: 0 val newAccountId = maxAccountId + 1 - activeAccount = AccountEntity(id = newAccountId, domain = domain.toLowerCase(), accessToken = accessToken, isActive = true) + activeAccount = AccountEntity(id = newAccountId, domain = domain.toLowerCase(Locale.ROOT), accessToken = accessToken, isActive = true) } @@ -146,8 +151,8 @@ class AccountManager(db: AppDatabase) { saveAccount(it) } - activeAccount = accounts.find { acc -> - acc.id == accountId + activeAccount = accounts.find { (id) -> + id == accountId } activeAccount?.let { @@ -185,8 +190,8 @@ class AccountManager(db: AppDatabase) { * @return the requested account or null if it was not found */ fun getAccountById(accountId: Long): AccountEntity? { - return accounts.find { acc -> - acc.id == accountId + return accounts.find { (id) -> + id == accountId } } diff --git a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt index bbc870614..69194c795 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/AppModule.kt @@ -21,10 +21,10 @@ import android.content.Context import android.content.SharedPreferences import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.preference.PreferenceManager +import androidx.room.Room import com.keylesspalace.tusky.TuskyApplication import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.EventHubImpl -import com.keylesspalace.tusky.db.AccountManager import com.keylesspalace.tusky.db.AppDatabase import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.network.TimelineCases @@ -64,20 +64,23 @@ class AppModule { return TimelineCasesImpl(api, eventHub) } - @Provides - @Singleton - fun providesAccountManager(app: TuskyApplication): AccountManager { - return app.serviceLocator.get(AccountManager::class.java) - } - @Provides @Singleton fun providesEventHub(): EventHub = EventHubImpl @Provides @Singleton - fun providesDatabase(app: TuskyApplication): AppDatabase { - return app.serviceLocator.get(AppDatabase::class.java) + fun providesDatabase(appContext: Context): AppDatabase { + return Room.databaseBuilder(appContext, AppDatabase::class.java, "tuskyDB") + .allowMainThreadQueries() + .addMigrations(AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5, + AppDatabase.MIGRATION_5_6, AppDatabase.MIGRATION_6_7, AppDatabase.MIGRATION_7_8, + AppDatabase.MIGRATION_8_9, AppDatabase.MIGRATION_9_10, AppDatabase.MIGRATION_10_11, + AppDatabase.MIGRATION_11_12, AppDatabase.MIGRATION_12_13, AppDatabase.MIGRATION_10_13, + AppDatabase.MIGRATION_13_14, AppDatabase.MIGRATION_14_15, AppDatabase.MIGRATION_15_16, + AppDatabase.MIGRATION_16_17, AppDatabase.MIGRATION_17_18, AppDatabase.MIGRATION_18_19, + AppDatabase.MIGRATION_19_20, AppDatabase.MIGRATION_20_21) + .build() } @Provides diff --git a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt index 26309be57..b349d50d9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/NetworkModule.kt @@ -13,14 +13,12 @@ * You should have received a copy of the GNU General Public License along with Tusky; if not, * see . */ - package com.keylesspalace.tusky.di import android.content.Context import android.text.Spanned import com.google.gson.Gson import com.google.gson.GsonBuilder -import com.google.gson.JsonDeserializer import com.keylesspalace.tusky.BuildConfig import com.keylesspalace.tusky.db.AccountManager import com.keylesspalace.tusky.json.SpannedTypeAdapter @@ -29,12 +27,8 @@ import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.util.OkHttpUtils import dagger.Module import dagger.Provides -import dagger.multibindings.ClassKey -import dagger.multibindings.IntoMap -import dagger.multibindings.IntoSet import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor -import retrofit2.Converter import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory @@ -47,32 +41,20 @@ import javax.inject.Singleton @Module class NetworkModule { - @Provides - @IntoMap - @ClassKey(Spanned::class) - fun providesSpannedTypeAdapter(): JsonDeserializer<*> = SpannedTypeAdapter() - @Provides @Singleton - fun providesGson(adapters: @JvmSuppressWildcards Map, JsonDeserializer<*>>): Gson { + fun providesGson(): Gson { return GsonBuilder() - .apply { - for ((k, v) in adapters) { - registerTypeAdapter(k, v) - } - } + .registerTypeAdapter(Spanned::class.java, SpannedTypeAdapter()) .create() } @Provides - @IntoSet @Singleton - fun providesConverterFactory(gson: Gson): Converter.Factory = GsonConverterFactory.create(gson) - - @Provides - @Singleton - fun providesHttpClient(accountManager: AccountManager, - context: Context): OkHttpClient { + fun providesHttpClient( + accountManager: AccountManager, + context: Context + ): OkHttpClient { return OkHttpUtils.getCompatibleClientBuilder(context) .apply { addInterceptor(InstanceSwitchAuthInterceptor(accountManager)) @@ -85,18 +67,14 @@ class NetworkModule { @Provides @Singleton - fun providesRetrofit(httpClient: OkHttpClient, - converters: @JvmSuppressWildcards Set): Retrofit { + fun providesRetrofit( + httpClient: OkHttpClient, + gson: Gson + ): Retrofit { return Retrofit.Builder().baseUrl("https://" + MastodonApi.PLACEHOLDER_DOMAIN) .client(httpClient) - .let { builder -> - // Doing it this way in case builder will be immutable so we return the final - // instance - converters.fold(builder) { b, c -> - b.addConverterFactory(c) - } - builder.addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) - } + .addConverterFactory(GsonConverterFactory.create(gson)) + .addCallAdapterFactory(RxJava2CallAdapterFactory.createAsync()) .build() } diff --git a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt index 386018b88..ac2e955a5 100644 --- a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt @@ -47,7 +47,7 @@ import org.robolectric.fakes.RoboMenuItem * Created by charlag on 3/7/18. */ -@Config(application = FakeTuskyApplication::class, sdk = [28]) +@Config(sdk = [28]) @RunWith(AndroidJUnit4::class) class ComposeActivityTest { private lateinit var activity: ComposeActivity diff --git a/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt b/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt deleted file mode 100644 index 640f6826b..000000000 --- a/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.keylesspalace.tusky - -/** - * Created by charlag on 3/7/18. - */ - -class FakeTuskyApplication : TuskyApplication() { - - private lateinit var locator: ServiceLocator - - override fun initSecurityProvider() { - // No-op - } - - override fun initAppInjector() { - // No-op - } - - override fun initNightMode() { - // No-op - } - - override fun getServiceLocator(): ServiceLocator { - return locator - } -} \ No newline at end of file diff --git a/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt b/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt index c94f26330..965eda674 100644 --- a/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/FilterTest.kt @@ -24,7 +24,7 @@ import retrofit2.Callback import retrofit2.Response import java.util.* -@Config(application = FakeTuskyApplication::class, sdk = [28]) +@Config(sdk = [28]) @RunWith(AndroidJUnit4::class) class FilterTest { diff --git a/app/src/test/java/com/keylesspalace/tusky/TuskyApplication.kt b/app/src/test/java/com/keylesspalace/tusky/TuskyApplication.kt new file mode 100644 index 000000000..aaa2b349e --- /dev/null +++ b/app/src/test/java/com/keylesspalace/tusky/TuskyApplication.kt @@ -0,0 +1,51 @@ +/* Copyright 2020 Tusky Contributors + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Tusky; if not, + * see . */ + +package com.keylesspalace.tusky + +import android.app.Application +import android.content.Context +import android.content.res.Configuration +import android.util.Log +import androidx.emoji.text.EmojiCompat +import com.keylesspalace.tusky.util.LocaleManager +import dagger.android.DispatchingAndroidInjector +import dagger.android.HasAndroidInjector +import de.c1710.filemojicompat.FileEmojiCompatConfig +import javax.inject.Inject + +// override TuskyApplication for Robolectric tests, only initialize the necessary stuff +class TuskyApplication : Application() { + + override fun onCreate() { + super.onCreate() + EmojiCompat.init(FileEmojiCompatConfig(this, "")) + } + + override fun attachBaseContext(base: Context) { + localeManager = LocaleManager(base) + super.attachBaseContext(localeManager.setLocale(base)) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + localeManager.setLocale(this) + } + + companion object { + @JvmStatic + lateinit var localeManager: LocaleManager + } +} \ No newline at end of file diff --git a/app/src/test/java/com/keylesspalace/tusky/di/AppInjector.kt b/app/src/test/java/com/keylesspalace/tusky/di/AppInjector.kt deleted file mode 100644 index 8a030aa1d..000000000 --- a/app/src/test/java/com/keylesspalace/tusky/di/AppInjector.kt +++ /dev/null @@ -1,2 +0,0 @@ -package com.keylesspalace.tusky.di - diff --git a/app/src/test/java/com/keylesspalace/tusky/util/RickRollTest.kt b/app/src/test/java/com/keylesspalace/tusky/util/RickRollTest.kt index c307e5524..b9b3a3740 100644 --- a/app/src/test/java/com/keylesspalace/tusky/util/RickRollTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/util/RickRollTest.kt @@ -2,7 +2,6 @@ package com.keylesspalace.tusky.util import android.app.Activity import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.keylesspalace.tusky.FakeTuskyApplication import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before @@ -11,7 +10,7 @@ import org.junit.runner.RunWith import org.robolectric.Robolectric import org.robolectric.annotation.Config -@Config(application = FakeTuskyApplication::class, sdk = [28]) +@Config(sdk = [28]) @RunWith(AndroidJUnit4::class) class RickRollTest { private lateinit var activity: Activity diff --git a/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt b/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt index acb6cf881..b85d60a1f 100644 --- a/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt @@ -2,14 +2,13 @@ package com.keylesspalace.tusky.util import android.text.SpannableStringBuilder import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.keylesspalace.tusky.FakeTuskyApplication import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config -@Config(application = FakeTuskyApplication::class, sdk = [28]) +@Config(sdk = [28]) @RunWith(AndroidJUnit4::class) class SmartLengthInputFilterTest { From d9c802982ed418a52d4809f1f3dbc6011dec912c Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Tue, 25 Feb 2020 19:49:41 +0100 Subject: [PATCH 13/16] Upgrade deps (#1708) * upgrade Dagger * upgrade AndroidX Lifecycle * upgrade AndroidX Fragment * upgrade Room, Retrofit, AndroidX core, Material components * fix report fragments not sharing viewmodels --- app/build.gradle | 19 ++++++++++--------- .../keylesspalace/tusky/AccountActivity.kt | 8 +++----- .../tusky/EditProfileActivity.kt | 6 ++---- .../components/compose/ComposeActivity.kt | 6 ++---- .../conversation/ConversationsFragment.kt | 12 +++++------- .../tusky/components/report/ReportActivity.kt | 7 ++----- .../report/fragments/ReportDoneFragment.kt | 17 ++++++----------- .../report/fragments/ReportNoteFragment.kt | 9 ++------- .../fragments/ReportStatusesFragment.kt | 10 ++-------- .../tusky/components/search/SearchActivity.kt | 5 ++--- .../search/fragments/SearchFragment.kt | 12 ++++-------- .../main/res/layout/activity_account_list.xml | 2 +- .../res/layout/activity_modal_timeline.xml | 2 +- .../main/res/layout/activity_preferences.xml | 2 +- .../main/res/layout/activity_statuslist.xml | 2 +- app/src/main/res/layout/activity_view_tag.xml | 2 +- .../main/res/layout/activity_view_thread.xml | 2 +- gradle.properties | 2 -- 18 files changed, 46 insertions(+), 79 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 59f6a5796..11f4474f6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -95,20 +95,20 @@ project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { } } -ext.lifecycleVersion = "2.1.0" -ext.roomVersion = '2.2.3' -ext.retrofitVersion = '2.6.0' +ext.lifecycleVersion = "2.2.0" +ext.roomVersion = '2.2.4' +ext.retrofitVersion = '2.7.1' ext.okhttpVersion = '4.3.1' ext.glideVersion = '4.10.0' -ext.daggerVersion = '2.25.3' +ext.daggerVersion = '2.26' // if libraries are changed here, they should also be changed in LicenseActivity dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation "androidx.core:core-ktx:1.2.0-rc01" + implementation "androidx.core:core-ktx:1.2.0" implementation "androidx.appcompat:appcompat:1.2.0-alpha02" - implementation "androidx.fragment:fragment-ktx:1.1.0" + implementation "androidx.fragment:fragment-ktx:1.2.2" implementation "androidx.browser:browser:1.2.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" implementation "androidx.recyclerview:recyclerview:1.1.0" @@ -118,8 +118,9 @@ dependencies { implementation "androidx.sharetarget:sharetarget:1.0.0-rc01" implementation "androidx.emoji:emoji:1.0.0" implementation "androidx.emoji:emoji-appcompat:1.0.0" - implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion" - implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycleVersion" implementation "androidx.constraintlayout:constraintlayout:1.1.3" implementation "androidx.paging:paging-runtime-ktx:2.1.1" implementation "androidx.viewpager2:viewpager2:1.0.0" @@ -127,7 +128,7 @@ dependencies { implementation "androidx.room:room-rxjava2:$roomVersion" kapt "androidx.room:room-compiler:$roomVersion" - implementation "com.google.android.material:material:1.1.0-rc01" + implementation "com.google.android.material:material:1.1.0" implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt index 4a1caaa26..ad91b19ec 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/AccountActivity.kt @@ -27,6 +27,7 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.activity.viewModels import androidx.annotation.ColorInt import androidx.annotation.Px import androidx.appcompat.app.AlertDialog @@ -34,7 +35,6 @@ import androidx.core.app.ActivityOptionsCompat import androidx.core.content.ContextCompat import androidx.emoji.text.EmojiCompat import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.viewpager2.widget.MarginPageTransformer @@ -76,7 +76,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI @Inject lateinit var viewModelFactory: ViewModelFactory - private lateinit var viewModel: AccountViewModel + private val viewModel: AccountViewModel by viewModels { viewModelFactory } private val accountFieldAdapter = AccountFieldAdapter(this) @@ -116,9 +116,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidI loadResources() makeNotificationBarTransparent() setContentView(R.layout.activity_account) - - viewModel = ViewModelProviders.of(this, viewModelFactory)[AccountViewModel::class.java] - + // Obtain information to fill out the profile. viewModel.setAccountInfo(intent.getStringExtra(KEY_ACCOUNT_ID)!!) diff --git a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt index 06f9c9b51..58da33df9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt @@ -19,7 +19,6 @@ import android.Manifest import android.app.Activity import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import android.content.Intent import android.content.pm.PackageManager import android.graphics.Bitmap @@ -34,6 +33,7 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.ImageView +import androidx.activity.viewModels import com.bumptech.glide.Glide import com.bumptech.glide.load.resource.bitmap.FitCenter import com.bumptech.glide.load.resource.bitmap.RoundedCorners @@ -69,7 +69,7 @@ class EditProfileActivity : BaseActivity(), Injectable { @Inject lateinit var viewModelFactory: ViewModelFactory - private lateinit var viewModel: EditProfileViewModel + private val viewModel: EditProfileViewModel by viewModels { viewModelFactory } private var currentlyPicking: PickType = PickType.NOTHING @@ -90,8 +90,6 @@ class EditProfileActivity : BaseActivity(), Injectable { setContentView(R.layout.activity_edit_profile) - viewModel = ViewModelProviders.of(this, viewModelFactory)[EditProfileViewModel::class.java] - setSupportActionBar(toolbar) supportActionBar?.run { setTitle(R.string.title_edit_profile) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt index 368819b88..d53bd6a57 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt @@ -37,6 +37,7 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.* +import androidx.activity.viewModels import androidx.annotation.ColorInt import androidx.annotation.StringRes import androidx.annotation.VisibleForTesting @@ -49,7 +50,6 @@ import androidx.core.view.inputmethod.InputContentInfoCompat import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import androidx.preference.PreferenceManager import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager @@ -109,7 +109,7 @@ class ComposeActivity : BaseActivity(), var maximumTootCharacters = DEFAULT_CHARACTER_LIMIT private var composeOptions: ComposeOptions? = null - private lateinit var viewModel: ComposeViewModel + private val viewModel: ComposeViewModel by viewModels { viewModelFactory } private var mediaCount = 0 @@ -141,8 +141,6 @@ class ComposeActivity : BaseActivity(), composeMediaPreviewBar.adapter = mediaAdapter composeMediaPreviewBar.itemAnimator = null - viewModel = ViewModelProviders.of(this, viewModelFactory)[ComposeViewModel::class.java] - subscribeToUpdates(mediaAdapter) setupButtons() diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt index 91f6550f2..fbc342810 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt @@ -20,8 +20,8 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.fragment.app.viewModels import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import androidx.paging.PagedList import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration @@ -50,15 +50,13 @@ class ConversationsFragment : SFragment(), StatusActionListener, Injectable, Res @Inject lateinit var db: AppDatabase - private lateinit var viewModel: ConversationsViewModel + private val viewModel: ConversationsViewModel by viewModels { viewModelFactory } private lateinit var adapter: ConversationAdapter private var layoutManager: LinearLayoutManager? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - viewModel = ViewModelProviders.of(this, viewModelFactory)[ConversationsViewModel::class.java] - return inflater.inflate(R.layout.fragment_timeline, container, false) } @@ -87,10 +85,10 @@ class ConversationsFragment : SFragment(), StatusActionListener, Injectable, Res initSwipeToRefresh() - viewModel.conversations.observe(this, Observer> { + viewModel.conversations.observe(viewLifecycleOwner, Observer> { adapter.submitList(it) }) - viewModel.networkState.observe(this, Observer { + viewModel.networkState.observe(viewLifecycleOwner, Observer { adapter.setNetworkState(it) }) @@ -99,7 +97,7 @@ class ConversationsFragment : SFragment(), StatusActionListener, Injectable, Res } private fun initSwipeToRefresh() { - viewModel.refreshState.observe(this, Observer { + viewModel.refreshState.observe(viewLifecycleOwner, Observer { swipeRefreshLayout.isRefreshing = it == NetworkState.LOADING }) swipeRefreshLayout.setOnRefreshListener { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/ReportActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/ReportActivity.kt index 7d3a378a2..5daf584b9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/report/ReportActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/report/ReportActivity.kt @@ -19,14 +19,12 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.MenuItem -import androidx.appcompat.content.res.AppCompatResources +import androidx.activity.viewModels import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import com.keylesspalace.tusky.BottomSheetActivity import com.keylesspalace.tusky.R import com.keylesspalace.tusky.components.report.adapter.ReportPagerAdapter import com.keylesspalace.tusky.di.ViewModelFactory -import com.keylesspalace.tusky.util.ThemeUtils import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector import kotlinx.android.synthetic.main.activity_report.* @@ -42,11 +40,10 @@ class ReportActivity : BottomSheetActivity(), HasAndroidInjector { @Inject lateinit var viewModelFactory: ViewModelFactory - private lateinit var viewModel: ReportViewModel + private val viewModel: ReportViewModel by viewModels { viewModelFactory } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - viewModel = ViewModelProviders.of(this, viewModelFactory)[ReportViewModel::class.java] val accountId = intent?.getStringExtra(ACCOUNT_ID) val accountUserName = intent?.getStringExtra(ACCOUNT_USERNAME) if (accountId.isNullOrBlank() || accountUserName.isNullOrBlank()) { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportDoneFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportDoneFragment.kt index 95bf73561..611231ecd 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportDoneFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportDoneFragment.kt @@ -21,8 +21,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import com.keylesspalace.tusky.R import com.keylesspalace.tusky.components.report.ReportViewModel import com.keylesspalace.tusky.components.report.Screen @@ -40,12 +40,7 @@ class ReportDoneFragment : Fragment(), Injectable { @Inject lateinit var viewModelFactory: ViewModelFactory - private lateinit var viewModel: ReportViewModel - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - viewModel = ViewModelProviders.of(requireActivity(), viewModelFactory)[ReportViewModel::class.java] - } + private val viewModel: ReportViewModel by viewModels({ requireActivity() }) { viewModelFactory } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -69,8 +64,8 @@ class ReportDoneFragment : Fragment(), Injectable { progressMute.hide() } - buttonMute.setText(when { - it.data == true -> R.string.action_unmute + buttonMute.setText(when (it.data) { + true -> R.string.action_unmute else -> R.string.action_mute }) }) @@ -84,8 +79,8 @@ class ReportDoneFragment : Fragment(), Injectable { buttonBlock.hide() progressBlock.hide() } - buttonBlock.setText(when { - it.data == true -> R.string.action_unblock + buttonBlock.setText(when (it.data) { + true -> R.string.action_unblock else -> R.string.action_block }) }) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportNoteFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportNoteFragment.kt index 9b0be6544..5a94ba176 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportNoteFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportNoteFragment.kt @@ -21,8 +21,8 @@ import android.view.View import android.view.ViewGroup import androidx.core.widget.doAfterTextChanged import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.R import com.keylesspalace.tusky.components.report.ReportViewModel @@ -39,12 +39,7 @@ class ReportNoteFragment : Fragment(), Injectable { @Inject lateinit var viewModelFactory: ViewModelFactory - private lateinit var viewModel: ReportViewModel - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - viewModel = ViewModelProviders.of(requireActivity(), viewModelFactory)[ReportViewModel::class.java] - } + private val viewModel: ReportViewModel by viewModels({ requireActivity() }) { viewModelFactory } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt index cc6ea00f3..3e9bd622d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/report/fragments/ReportStatusesFragment.kt @@ -22,8 +22,8 @@ import android.view.ViewGroup import androidx.core.app.ActivityOptionsCompat import androidx.core.view.ViewCompat import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import androidx.paging.PagedList import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DividerItemDecoration @@ -59,19 +59,13 @@ class ReportStatusesFragment : Fragment(), Injectable, AdapterHandler { @Inject lateinit var accountManager: AccountManager - private lateinit var viewModel: ReportViewModel + private val viewModel: ReportViewModel by viewModels({ requireActivity() }) { viewModelFactory } private lateinit var adapter: StatusesAdapter private lateinit var layoutManager: LinearLayoutManager private var snackbarErrorRetry: Snackbar? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - viewModel = ViewModelProviders.of(requireActivity(), viewModelFactory)[ReportViewModel::class.java] - } - override fun showMedia(v: View?, status: Status?, idx: Int) { status?.actionableStatus?.let { actionable -> when (actionable.attachments[idx].type) { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt index 6da50940e..db31e49fa 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchActivity.kt @@ -21,8 +21,8 @@ import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem +import androidx.activity.viewModels import androidx.appcompat.widget.SearchView -import androidx.lifecycle.ViewModelProviders import com.google.android.material.tabs.TabLayoutMediator import com.keylesspalace.tusky.BottomSheetActivity import com.keylesspalace.tusky.R @@ -40,12 +40,11 @@ class SearchActivity : BottomSheetActivity(), HasAndroidInjector { @Inject lateinit var viewModelFactory: ViewModelFactory - private lateinit var viewModel: SearchViewModel + private val viewModel: SearchViewModel by viewModels { viewModelFactory } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_search) - viewModel = ViewModelProviders.of(this, viewModelFactory)[SearchViewModel::class.java] setSupportActionBar(toolbar) supportActionBar?.apply { setDisplayHomeAsUpEnabled(true) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt index b4a36e2ad..45fa4d6e7 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchFragment.kt @@ -5,9 +5,9 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import androidx.paging.PagedList import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DividerItemDecoration @@ -30,11 +30,12 @@ import javax.inject.Inject abstract class SearchFragment : Fragment(), LinkListener, Injectable, SwipeRefreshLayout.OnRefreshListener { - private var snackbarErrorRetry: Snackbar? = null @Inject lateinit var viewModelFactory: ViewModelFactory - protected lateinit var viewModel: SearchViewModel + protected val viewModel: SearchViewModel by viewModels({ requireActivity() }) { viewModelFactory } + + private var snackbarErrorRetry: Snackbar? = null abstract fun createAdapter(): PagedListAdapter @@ -43,11 +44,6 @@ abstract class SearchFragment : Fragment(), abstract val data: LiveData> protected lateinit var adapter: PagedListAdapter - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - viewModel = ViewModelProviders.of(requireActivity(), viewModelFactory)[SearchViewModel::class.java] - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_search, container, false) } diff --git a/app/src/main/res/layout/activity_account_list.xml b/app/src/main/res/layout/activity_account_list.xml index 67cb0a7e3..fb6174977 100644 --- a/app/src/main/res/layout/activity_account_list.xml +++ b/app/src/main/res/layout/activity_account_list.xml @@ -9,7 +9,7 @@ - - - - - - Date: Tue, 25 Feb 2020 19:57:28 +0100 Subject: [PATCH 14/16] Make image in BackgroundMessageView adapt to the height, fix #1618 (#1649) * Make image in BackgroundMessageView adapt to the height, fix #1618 * Hide filters panel when showing status view in notifications --- .../tusky/fragment/NotificationsFragment.java | 8 +++++++- .../tusky/view/BackgroundMessageView.kt | 2 +- app/src/main/res/layout/activity_lists.xml | 4 +++- app/src/main/res/layout/fragment_timeline.xml | 3 ++- .../layout/fragment_timeline_notifications.xml | 2 +- .../main/res/layout/view_background_message.xml | 17 +++++++++++++++-- 6 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java index d82a86a72..64805a6a9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java @@ -167,6 +167,7 @@ public class NotificationsFragment extends SFragment implements private boolean alwaysShowSensitiveMedia; private boolean alwaysOpenSpoiler; private boolean showNotificationsFilter; + private boolean showingError; // Each element is either a Notification for loading data or a Placeholder private final PairedList, NotificationViewData> notifications @@ -280,7 +281,7 @@ public class NotificationsFragment extends SFragment implements private void updateFilterVisibility() { CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) swipeRefreshLayout.getLayoutParams(); - if (showNotificationsFilter) { + if (showNotificationsFilter && !showingError && !notifications.isEmpty()) { appBarOptions.setExpanded(true, false); appBarOptions.setVisibility(View.VISIBLE); //Set content behaviour to hide filter on scroll @@ -392,6 +393,7 @@ public class NotificationsFragment extends SFragment implements @Override public void onRefresh() { this.statusView.setVisibility(View.GONE); + this.showingError = false; Either first = CollectionsKt.firstOrNull(this.notifications); String topId; if (first != null && first.isRight()) { @@ -669,6 +671,7 @@ public class NotificationsFragment extends SFragment implements //Show friend elephant this.statusView.setVisibility(View.VISIBLE); this.statusView.setup(R.drawable.elephant_friend_empty, R.string.message_empty, null); + updateFilterVisibility(); //Update adapter updateAdapter(); @@ -994,6 +997,7 @@ public class NotificationsFragment extends SFragment implements } else { swipeRefreshLayout.setEnabled(true); } + updateFilterVisibility(); swipeRefreshLayout.setRefreshing(false); progressBar.setVisibility(View.GONE); } @@ -1009,6 +1013,7 @@ public class NotificationsFragment extends SFragment implements } else if (this.notifications.isEmpty()) { this.statusView.setVisibility(View.VISIBLE); swipeRefreshLayout.setEnabled(false); + this.showingError = true; if (exception instanceof IOException) { this.statusView.setup(R.drawable.elephant_offline, R.string.error_network, __ -> { this.progressBar.setVisibility(View.VISIBLE); @@ -1022,6 +1027,7 @@ public class NotificationsFragment extends SFragment implements return Unit.INSTANCE; }); } + updateFilterVisibility(); } Log.e(TAG, "Fetch failure: " + exception.getMessage()); diff --git a/app/src/main/java/com/keylesspalace/tusky/view/BackgroundMessageView.kt b/app/src/main/java/com/keylesspalace/tusky/view/BackgroundMessageView.kt index e39566f4b..4789ac3c1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/view/BackgroundMessageView.kt +++ b/app/src/main/java/com/keylesspalace/tusky/view/BackgroundMessageView.kt @@ -39,7 +39,7 @@ class BackgroundMessageView @JvmOverloads constructor( fun setup(@DrawableRes imageRes: Int, @StringRes messageRes: Int, clickListener: ((v: View) -> Unit)? = null) { messageTextView.setText(messageRes) - messageTextView.setCompoundDrawablesWithIntrinsicBounds(0, imageRes, 0, 0) + imageView.setImageResource(imageRes) button.setOnClickListener(clickListener) button.visible(clickListener != null) } diff --git a/app/src/main/res/layout/activity_lists.xml b/app/src/main/res/layout/activity_lists.xml index 45b010662..663d90d25 100644 --- a/app/src/main/res/layout/activity_lists.xml +++ b/app/src/main/res/layout/activity_lists.xml @@ -39,7 +39,9 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@id/appbar" + tools:visibility="visible" + app:layout_constrainedHeight="true" /> diff --git a/app/src/main/res/layout/fragment_timeline.xml b/app/src/main/res/layout/fragment_timeline.xml index 0b5c57b8d..79f7fdb37 100644 --- a/app/src/main/res/layout/fragment_timeline.xml +++ b/app/src/main/res/layout/fragment_timeline.xml @@ -36,7 +36,8 @@ app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" - tools:visibility="visible" /> + tools:visibility="visible" + app:layout_constrainedHeight="true" /> + xmlns:tools="http://schemas.android.com/tools" + tools:gravity="center_horizontal" + tools:orientation="vertical" + tools:parentTag="android.widget.LinearLayout"> + +