diff --git a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java
index 62bb8d684..0837b5e8d 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java
@@ -19,6 +19,7 @@ import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentContainerView;
+import de.danoeh.antennapod.ui.echo.EchoConfig;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@@ -37,7 +38,6 @@ import de.danoeh.antennapod.event.FeedListUpdateEvent;
import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.fragment.SearchFragment;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.ui.echo.EchoActivity;
import de.danoeh.antennapod.ui.home.sections.AllowNotificationsSection;
import de.danoeh.antennapod.ui.home.sections.DownloadsSection;
import de.danoeh.antennapod.ui.home.sections.EchoSection;
@@ -98,10 +98,10 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis
addSection(new AllowNotificationsSection());
}
}
- if (Calendar.getInstance().get(Calendar.YEAR) == EchoActivity.RELEASE_YEAR
+ if (Calendar.getInstance().get(Calendar.YEAR) == EchoConfig.RELEASE_YEAR
&& Calendar.getInstance().get(Calendar.MONTH) == Calendar.DECEMBER
&& Calendar.getInstance().get(Calendar.DAY_OF_MONTH) >= 10
- && prefs.getInt(PREF_HIDE_ECHO, 0) != EchoActivity.RELEASE_YEAR) {
+ && prefs.getInt(PREF_HIDE_ECHO, 0) != EchoConfig.RELEASE_YEAR) {
addSection(new EchoSection());
}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/home/sections/EchoSection.java b/app/src/main/java/de/danoeh/antennapod/ui/home/sections/EchoSection.java
index 0a03db7f4..28ff05512 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/home/sections/EchoSection.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/home/sections/EchoSection.java
@@ -11,18 +11,17 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.databinding.HomeSectionEchoBinding;
import de.danoeh.antennapod.storage.database.DBReader;
import de.danoeh.antennapod.storage.database.StatisticsItem;
-import de.danoeh.antennapod.databinding.HomeSectionEchoBinding;
import de.danoeh.antennapod.ui.echo.EchoActivity;
+import de.danoeh.antennapod.ui.echo.EchoConfig;
import de.danoeh.antennapod.ui.home.HomeFragment;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import java.util.Calendar;
-
public class EchoSection extends Fragment {
private HomeSectionEchoBinding viewBinding;
private Disposable disposable;
@@ -32,32 +31,21 @@ public class EchoSection extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
viewBinding = HomeSectionEchoBinding.inflate(inflater);
- viewBinding.titleLabel.setText(getString(R.string.antennapod_echo_year, EchoActivity.RELEASE_YEAR));
+ viewBinding.titleLabel.setText(getString(R.string.antennapod_echo_year, EchoConfig.RELEASE_YEAR));
viewBinding.echoButton.setOnClickListener(v -> startActivity(new Intent(getContext(), EchoActivity.class)));
viewBinding.closeButton.setOnClickListener(v -> hideThisYear());
updateVisibility();
return viewBinding.getRoot();
}
- private long jan1() {
- Calendar date = Calendar.getInstance();
- date.set(Calendar.HOUR_OF_DAY, 0);
- date.set(Calendar.MINUTE, 0);
- date.set(Calendar.SECOND, 0);
- date.set(Calendar.MILLISECOND, 0);
- date.set(Calendar.DAY_OF_MONTH, 1);
- date.set(Calendar.MONTH, 0);
- date.set(Calendar.YEAR, EchoActivity.RELEASE_YEAR);
- return date.getTimeInMillis();
- }
-
private void updateVisibility() {
if (disposable != null) {
disposable.dispose();
}
disposable = Observable.fromCallable(
() -> {
- DBReader.StatisticsResult statisticsResult = DBReader.getStatistics(false, jan1(), Long.MAX_VALUE);
+ DBReader.StatisticsResult statisticsResult = DBReader.getStatistics(
+ false, EchoConfig.jan1(), Long.MAX_VALUE);
long totalTime = 0;
for (StatisticsItem feedTime : statisticsResult.feedTime) {
totalTime += feedTime.timePlayed;
@@ -77,7 +65,7 @@ public class EchoSection extends Fragment {
void hideThisYear() {
getContext().getSharedPreferences(HomeFragment.PREF_NAME, Context.MODE_PRIVATE)
- .edit().putInt(HomeFragment.PREF_HIDE_ECHO, EchoActivity.RELEASE_YEAR).apply();
+ .edit().putInt(HomeFragment.PREF_HIDE_ECHO, EchoConfig.RELEASE_YEAR).apply();
((MainActivity) getActivity()).loadFragment(HomeFragment.TAG, null);
}
}
diff --git a/config/spotbugs/exclude.xml b/config/spotbugs/exclude.xml
index 5bc7169e9..e4902dc1b 100644
--- a/config/spotbugs/exclude.xml
+++ b/config/spotbugs/exclude.xml
@@ -26,7 +26,7 @@
-
+
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoActivity.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoActivity.java
index bfe5fbf98..33bf85aaa 100644
--- a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoActivity.java
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoActivity.java
@@ -1,97 +1,60 @@
package de.danoeh.antennapod.ui.echo;
import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.Bundle;
-import android.text.format.DateFormat;
import android.util.Log;
import android.view.KeyEvent;
-import android.view.View;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.app.ShareCompat;
-import androidx.core.content.FileProvider;
import androidx.core.view.WindowCompat;
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
-import com.bumptech.glide.request.RequestOptions;
-import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.storage.database.DBReader;
-import de.danoeh.antennapod.storage.database.StatisticsItem;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.ui.common.Converter;
import de.danoeh.antennapod.ui.echo.databinding.EchoActivityBinding;
-import de.danoeh.antennapod.ui.echo.screens.BubbleScreen;
-import de.danoeh.antennapod.ui.echo.screens.FinalShareScreen;
-import de.danoeh.antennapod.ui.echo.screens.RotatingSquaresScreen;
-import de.danoeh.antennapod.ui.echo.screens.StripesScreen;
-import de.danoeh.antennapod.ui.echo.screens.WaveformScreen;
-import de.danoeh.antennapod.ui.echo.screens.WavesScreen;
-import de.danoeh.antennapod.ui.episodes.PlaybackSpeedUtils;
+import de.danoeh.antennapod.ui.echo.screen.EchoScreen;
+import de.danoeh.antennapod.ui.echo.screen.FinalShareScreen;
+import de.danoeh.antennapod.ui.echo.screen.HoarderScreen;
+import de.danoeh.antennapod.ui.echo.screen.HoursPlayedScreen;
+import de.danoeh.antennapod.ui.echo.screen.IntroScreen;
+import de.danoeh.antennapod.ui.echo.screen.QueueScreen;
+import de.danoeh.antennapod.ui.echo.screen.ThanksScreen;
+import de.danoeh.antennapod.ui.echo.screen.TimeReleasePlayScreen;
import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
import java.util.Collections;
-import java.util.Date;
import java.util.List;
-import java.util.Locale;
import java.util.concurrent.TimeUnit;
public class EchoActivity extends AppCompatActivity {
- public static final int RELEASE_YEAR = 2023;
private static final String TAG = "EchoActivity";
private static final int NUM_SCREENS = 7;
- private static final int SHARE_SIZE = 1000;
private EchoActivityBinding viewBinding;
- private int currentScreen = -1;
+ private int currentScreenIdx = -1;
private boolean progressPaused = false;
private float progress = 0;
- private Drawable currentDrawable;
private EchoProgress echoProgress;
private Disposable redrawTimer;
private long timeTouchDown;
private long timeLastFrame;
private Disposable disposable;
- private Disposable disposableFavorite;
-
- private long totalTime = 0;
- private int totalActivePodcasts = 0;
- private int playedPodcasts = 0;
- private int playedActivePodcasts = 0;
- private String randomUnplayedActivePodcast = "";
- private int queueNumEpisodes = 0;
- private long queueSecondsLeft = 0;
- private long timeBetweenReleaseAndPlay = 0;
- private long oldestDate = 0;
- private final ArrayList favoritePodNames = new ArrayList<>();
- private final ArrayList favoritePodImages = new ArrayList<>();
+ private List screens;
+ private EchoScreen currentScreen;
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
super.onCreate(savedInstanceState);
+ screens = List.of(new IntroScreen(this, getLayoutInflater()),
+ new HoursPlayedScreen(this, getLayoutInflater()), new QueueScreen(this, getLayoutInflater()),
+ new TimeReleasePlayScreen(this, getLayoutInflater()), new HoarderScreen(this, getLayoutInflater()),
+ new ThanksScreen(this, getLayoutInflater()), new FinalShareScreen(this, getLayoutInflater()));
viewBinding = EchoActivityBinding.inflate(getLayoutInflater());
viewBinding.closeButton.setOnClickListener(v -> finish());
- viewBinding.shareButton.setOnClickListener(v -> share());
- viewBinding.echoImage.setOnTouchListener((v, event) -> {
+ viewBinding.screenContainer.setOnTouchListener((v, event) -> {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
progressPaused = true;
timeTouchDown = System.currentTimeMillis();
@@ -99,11 +62,11 @@ public class EchoActivity extends AppCompatActivity {
progressPaused = false;
if (timeTouchDown + 500 > System.currentTimeMillis()) {
int newScreen;
- if (event.getX() < 0.5f * viewBinding.echoImage.getMeasuredWidth()) {
- newScreen = Math.max(currentScreen - 1, 0);
+ if (event.getX() < 0.5f * viewBinding.screenContainer.getMeasuredWidth()) {
+ newScreen = Math.max(currentScreenIdx - 1, 0);
} else {
- newScreen = Math.min(currentScreen + 1, NUM_SCREENS - 1);
- if (currentScreen == NUM_SCREENS - 1) {
+ newScreen = Math.min(currentScreenIdx + 1, NUM_SCREENS - 1);
+ if (currentScreenIdx == NUM_SCREENS - 1) {
finish();
}
}
@@ -121,35 +84,9 @@ public class EchoActivity extends AppCompatActivity {
loadStatistics();
}
- private void share() {
- try {
- Bitmap bitmap = Bitmap.createBitmap(SHARE_SIZE, SHARE_SIZE, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- currentDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- currentDrawable.draw(canvas);
- viewBinding.echoImage.setImageDrawable(null);
- viewBinding.echoImage.setImageDrawable(currentDrawable);
- File file = new File(UserPreferences.getDataFolder(null), "AntennaPodEcho.png");
- FileOutputStream stream = new FileOutputStream(file);
- bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
- stream.close();
-
- Uri fileUri = FileProvider.getUriForFile(this, getString(R.string.provider_authority), file);
- new ShareCompat.IntentBuilder(this)
- .setType("image/png")
- .addStream(fileUri)
- .setText(getString(R.string.echo_share, RELEASE_YEAR))
- .setChooserTitle(R.string.share_file_label)
- .startChooser();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
@Override
protected void onStart() {
super.onStart();
-
redrawTimer = Flowable.timer(20, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.io())
.repeat()
@@ -157,7 +94,7 @@ public class EchoActivity extends AppCompatActivity {
if (progressPaused) {
return;
}
- viewBinding.echoImage.postInvalidate();
+ currentScreen.postInvalidate();
if (progress >= NUM_SCREENS - 0.001f) {
return;
}
@@ -180,254 +117,38 @@ public class EchoActivity extends AppCompatActivity {
if (disposable != null) {
disposable.dispose();
}
- if (disposableFavorite != null) {
- disposableFavorite.dispose();
- }
}
private void loadScreen(int screen, boolean force) {
- if (screen == currentScreen && !force) {
+ if (screen == currentScreenIdx && !force) {
return;
}
- currentScreen = screen;
+ currentScreenIdx = screen;
+ currentScreen = screens.get(currentScreenIdx);
runOnUiThread(() -> {
- viewBinding.echoLogo.setVisibility(currentScreen == 0 ? View.VISIBLE : View.GONE);
- viewBinding.shareButton.setVisibility(currentScreen == 6 ? View.VISIBLE : View.GONE);
-
- switch (currentScreen) {
- case 0:
- viewBinding.aboveLabel.setText(R.string.echo_intro_your_year);
- viewBinding.largeLabel.setText(String.format(getEchoLanguage(), "%d", RELEASE_YEAR));
- viewBinding.belowLabel.setText(R.string.echo_intro_in_podcasts);
- viewBinding.smallLabel.setText(R.string.echo_intro_locally);
- currentDrawable = new BubbleScreen(this);
- break;
- case 1:
- viewBinding.aboveLabel.setText(R.string.echo_hours_this_year);
- viewBinding.largeLabel.setText(String.format(getEchoLanguage(), "%d", totalTime / 3600));
- viewBinding.belowLabel.setText(getResources()
- .getQuantityString(R.plurals.echo_hours_podcasts, playedPodcasts, playedPodcasts));
- viewBinding.smallLabel.setText("");
- currentDrawable = new WaveformScreen(this);
- break;
- case 2:
- viewBinding.largeLabel.setText(String.format(getEchoLanguage(), "%d", queueSecondsLeft / 3600));
- viewBinding.belowLabel.setText(getResources().getQuantityString(
- R.plurals.echo_queue_hours_waiting, queueNumEpisodes, queueNumEpisodes));
- Calendar dec31 = Calendar.getInstance();
- dec31.set(Calendar.DAY_OF_MONTH, 31);
- dec31.set(Calendar.MONTH, Calendar.DECEMBER);
- int daysUntilNextYear = Math.max(1,
- dec31.get(Calendar.DAY_OF_YEAR) - Calendar.getInstance().get(Calendar.DAY_OF_YEAR) + 1);
- long secondsPerDay = queueSecondsLeft / daysUntilNextYear;
- String timePerDay = Converter.getDurationStringLocalized(
- getLocalizedResources(this, getEchoLanguage()), secondsPerDay * 1000, true);
- double hoursPerDay = secondsPerDay / 3600.0;
- int nextYear = RELEASE_YEAR + 1;
- if (hoursPerDay < 1.5) {
- viewBinding.aboveLabel.setText(R.string.echo_queue_title_clean);
- viewBinding.smallLabel.setText(
- getString(R.string.echo_queue_hours_clean, timePerDay, nextYear));
- } else if (hoursPerDay <= 24) {
- viewBinding.aboveLabel.setText(R.string.echo_queue_title_many);
- viewBinding.smallLabel.setText(
- getString(R.string.echo_queue_hours_normal, timePerDay, nextYear));
- } else {
- viewBinding.aboveLabel.setText(R.string.echo_queue_title_many);
- viewBinding.smallLabel.setText(getString(R.string.echo_queue_hours_much, timePerDay, nextYear));
- }
- currentDrawable = new StripesScreen(this);
- break;
- case 3:
- viewBinding.aboveLabel.setText(R.string.echo_listened_after_title);
- if (timeBetweenReleaseAndPlay <= 1000L * 3600 * 24 * 2.5) {
- viewBinding.largeLabel.setText(R.string.echo_listened_after_emoji_run);
- viewBinding.belowLabel.setText(R.string.echo_listened_after_comment_addict);
- } else {
- viewBinding.largeLabel.setText(R.string.echo_listened_after_emoji_yoga);
- viewBinding.belowLabel.setText(R.string.echo_listened_after_comment_easy);
- }
- viewBinding.smallLabel.setText(getString(R.string.echo_listened_after_time,
- Converter.getDurationStringLocalized(
- getLocalizedResources(this, getEchoLanguage()), timeBetweenReleaseAndPlay, true)));
- currentDrawable = new RotatingSquaresScreen(this);
- break;
- case 4:
- viewBinding.aboveLabel.setText(R.string.echo_hoarder_title);
- int percentagePlayed = (int) (100.0 * playedActivePodcasts / totalActivePodcasts);
- if (percentagePlayed < 25) {
- viewBinding.largeLabel.setText(R.string.echo_hoarder_emoji_cabinet);
- viewBinding.belowLabel.setText(R.string.echo_hoarder_subtitle_hoarder);
- viewBinding.smallLabel.setText(getString(R.string.echo_hoarder_comment_hoarder,
- percentagePlayed, totalActivePodcasts));
- } else if (percentagePlayed < 75) {
- viewBinding.largeLabel.setText(R.string.echo_hoarder_emoji_check);
- viewBinding.belowLabel.setText(R.string.echo_hoarder_subtitle_medium);
- viewBinding.smallLabel.setText(getString(R.string.echo_hoarder_comment_medium,
- percentagePlayed, totalActivePodcasts, randomUnplayedActivePodcast));
- } else {
- viewBinding.largeLabel.setText(R.string.echo_hoarder_emoji_clean);
- viewBinding.belowLabel.setText(R.string.echo_hoarder_subtitle_clean);
- viewBinding.smallLabel.setText(getString(R.string.echo_hoarder_comment_clean,
- percentagePlayed, totalActivePodcasts));
- }
- currentDrawable = new WavesScreen(this);
- break;
- case 5:
- viewBinding.aboveLabel.setText("");
- viewBinding.largeLabel.setText(R.string.echo_thanks_large);
- if (oldestDate < jan1()) {
- String skeleton = DateFormat.getBestDateTimePattern(getEchoLanguage(), "MMMM yyyy");
- SimpleDateFormat dateFormat = new SimpleDateFormat(skeleton, getEchoLanguage());
- String dateFrom = dateFormat.format(new Date(oldestDate));
- viewBinding.belowLabel.setText(getString(R.string.echo_thanks_we_are_glad_old, dateFrom));
- } else {
- viewBinding.belowLabel.setText(R.string.echo_thanks_we_are_glad_new);
- }
- viewBinding.smallLabel.setText(R.string.echo_thanks_now_favorite);
- currentDrawable = new RotatingSquaresScreen(this);
- break;
- case 6:
- viewBinding.aboveLabel.setText("");
- viewBinding.largeLabel.setText("");
- viewBinding.belowLabel.setText("");
- viewBinding.smallLabel.setText("");
- currentDrawable = new FinalShareScreen(this, favoritePodNames, favoritePodImages);
- break;
- default: // Keep
- }
- viewBinding.echoImage.setImageDrawable(currentDrawable);
+ viewBinding.screenContainer.removeAllViews();
+ viewBinding.screenContainer.addView(currentScreen.getView());
});
}
- private Locale getEchoLanguage() {
- boolean hasTranslation = !getString(R.string.echo_listened_after_title)
- .equals(getLocalizedResources(this, Locale.US).getString(R.string.echo_listened_after_title));
- if (hasTranslation) {
- return Locale.getDefault();
- } else {
- return Locale.US;
- }
- }
-
- @NonNull
- private Resources getLocalizedResources(Context context, Locale desiredLocale) {
- Configuration conf = context.getResources().getConfiguration();
- conf = new Configuration(conf);
- conf.setLocale(desiredLocale);
- Context localizedContext = context.createConfigurationContext(conf);
- return localizedContext.getResources();
- }
-
- private long jan1() {
- Calendar date = Calendar.getInstance();
- date.set(Calendar.HOUR_OF_DAY, 0);
- date.set(Calendar.MINUTE, 0);
- date.set(Calendar.SECOND, 0);
- date.set(Calendar.MILLISECOND, 0);
- date.set(Calendar.DAY_OF_MONTH, 1);
- date.set(Calendar.MONTH, 0);
- date.set(Calendar.YEAR, RELEASE_YEAR);
- return date.getTimeInMillis();
- }
-
private void loadStatistics() {
if (disposable != null) {
disposable.dispose();
}
- long timeFilterFrom = jan1();
- long timeFilterTo = Long.MAX_VALUE;
disposable = Observable.fromCallable(
() -> {
DBReader.StatisticsResult statisticsData = DBReader.getStatistics(
- false, timeFilterFrom, timeFilterTo);
+ false, EchoConfig.jan1(), Long.MAX_VALUE);
Collections.sort(statisticsData.feedTime, (item1, item2) ->
Long.compare(item2.timePlayed, item1.timePlayed));
-
- favoritePodNames.clear();
- for (int i = 0; i < 5 && i < statisticsData.feedTime.size(); i++) {
- favoritePodNames.add(statisticsData.feedTime.get(i).feed.getTitle());
- }
- loadFavoritePodImages(statisticsData);
-
- totalActivePodcasts = 0;
- playedActivePodcasts = 0;
- playedPodcasts = 0;
- totalTime = 0;
- ArrayList unplayedActive = new ArrayList<>();
- for (StatisticsItem item : statisticsData.feedTime) {
- totalTime += item.timePlayed;
- if (item.timePlayed > 0) {
- playedPodcasts++;
- }
- if (item.feed.getPreferences().getKeepUpdated()) {
- totalActivePodcasts++;
- if (item.timePlayed > 0) {
- playedActivePodcasts++;
- } else {
- unplayedActive.add(item.feed.getTitle());
- }
- }
- }
- if (!unplayedActive.isEmpty()) {
- randomUnplayedActivePodcast = unplayedActive.get((int) (Math.random() * unplayedActive.size()));
- }
-
- List queue = DBReader.getQueue();
- queueNumEpisodes = queue.size();
- queueSecondsLeft = 0;
- for (FeedItem item : queue) {
- float playbackSpeed = 1;
- if (UserPreferences.timeRespectsSpeed()) {
- playbackSpeed = PlaybackSpeedUtils.getCurrentPlaybackSpeed(item.getMedia());
- }
- if (item.getMedia() != null) {
- long itemTimeLeft = item.getMedia().getDuration() - item.getMedia().getPosition();
- queueSecondsLeft += itemTimeLeft / playbackSpeed;
- }
- }
- queueSecondsLeft /= 1000;
-
- timeBetweenReleaseAndPlay = DBReader.getTimeBetweenReleaseAndPlayback(timeFilterFrom, timeFilterTo);
- oldestDate = statisticsData.oldestDate;
return statisticsData;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> loadScreen(currentScreen, true),
- error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
-
- void loadFavoritePodImages(DBReader.StatisticsResult statisticsData) {
- if (disposableFavorite != null) {
- disposableFavorite.dispose();
- }
- disposableFavorite = Observable.fromCallable(
- () -> {
- favoritePodImages.clear();
- for (int i = 0; i < 5 && i < statisticsData.feedTime.size(); i++) {
- BitmapDrawable cover = new BitmapDrawable(getResources(), (Bitmap) null);
- try {
- final int size = SHARE_SIZE / 3;
- final int radius = (i == 0) ? (size / 16) : (size / 8);
- cover = new BitmapDrawable(getResources(), Glide.with(this)
- .asBitmap()
- .load(statisticsData.feedTime.get(i).feed.getImageUrl())
- .apply(new RequestOptions()
- .fitCenter()
- .transform(new RoundedCorners(radius)))
- .submit(size, size)
- .get(5, TimeUnit.SECONDS));
- } catch (Exception e) {
- Log.d(TAG, "Loading cover: " + e.getMessage());
- }
- favoritePodImages.add(cover);
+ .subscribe(result -> {
+ for (EchoScreen screen : screens) {
+ screen.startLoading(result);
}
- return statisticsData;
- })
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> { },
- error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
}
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoConfig.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoConfig.java
new file mode 100644
index 000000000..2a93ab063
--- /dev/null
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/EchoConfig.java
@@ -0,0 +1,19 @@
+package de.danoeh.antennapod.ui.echo;
+
+import java.util.Calendar;
+
+public class EchoConfig {
+ public static final int RELEASE_YEAR = 2023;
+
+ public static long jan1() {
+ Calendar date = Calendar.getInstance();
+ date.set(Calendar.HOUR_OF_DAY, 0);
+ date.set(Calendar.MINUTE, 0);
+ date.set(Calendar.SECOND, 0);
+ date.set(Calendar.MILLISECOND, 0);
+ date.set(Calendar.DAY_OF_MONTH, 1);
+ date.set(Calendar.MONTH, 0);
+ date.set(Calendar.YEAR, RELEASE_YEAR);
+ return date.getTimeInMillis();
+ }
+}
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/BaseScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/BaseBackground.java
similarity index 95%
rename from ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/BaseScreen.java
rename to ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/BaseBackground.java
index e8bc085cd..343ce4547 100644
--- a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/BaseScreen.java
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/BaseBackground.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.ui.echo.screens;
+package de.danoeh.antennapod.ui.echo.background;
import android.content.Context;
import android.graphics.Canvas;
@@ -14,7 +14,7 @@ import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import de.danoeh.antennapod.ui.echo.R;
-public abstract class BaseScreen extends Drawable {
+public abstract class BaseBackground extends Drawable {
private final Paint paintBackground;
protected final Paint paintParticles;
protected final ArrayList particles = new ArrayList<>();
@@ -22,7 +22,7 @@ public abstract class BaseScreen extends Drawable {
private final int colorBackgroundTo;
private long lastFrame = 0;
- public BaseScreen(Context context) {
+ public BaseBackground(Context context) {
colorBackgroundFrom = ContextCompat.getColor(context, R.color.gradient_000);
colorBackgroundTo = ContextCompat.getColor(context, R.color.gradient_100);
paintBackground = new Paint();
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/BubbleScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/BubbleBackground.java
similarity index 88%
rename from ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/BubbleScreen.java
rename to ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/BubbleBackground.java
index bd79645dc..28d6cb4e2 100644
--- a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/BubbleScreen.java
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/BubbleBackground.java
@@ -1,14 +1,14 @@
-package de.danoeh.antennapod.ui.echo.screens;
+package de.danoeh.antennapod.ui.echo.background;
import android.content.Context;
import android.graphics.Canvas;
import androidx.annotation.NonNull;
-public class BubbleScreen extends BaseScreen {
+public class BubbleBackground extends BaseBackground {
protected static final double PARTICLE_SPEED = 0.00002;
protected static final int NUM_PARTICLES = 15;
- public BubbleScreen(Context context) {
+ public BubbleBackground(Context context) {
super(context);
for (int i = 0; i < NUM_PARTICLES; i++) {
particles.add(new Particle(Math.random(), 2.0 * Math.random() - 0.5, // Could already be off-screen
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/FinalShareScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/FinalShareBackground.java
similarity index 93%
rename from ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/FinalShareScreen.java
rename to ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/FinalShareBackground.java
index 4af8941d0..341bc5133 100644
--- a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/FinalShareScreen.java
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/FinalShareBackground.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.ui.echo.screens;
+package de.danoeh.antennapod.ui.echo.background;
import android.content.Context;
import android.graphics.Canvas;
@@ -9,11 +9,11 @@ import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.res.ResourcesCompat;
-import de.danoeh.antennapod.ui.echo.EchoActivity;
+import de.danoeh.antennapod.ui.echo.EchoConfig;
import de.danoeh.antennapod.ui.echo.R;
import java.util.ArrayList;
-public class FinalShareScreen extends BubbleScreen {
+public class FinalShareBackground extends BubbleBackground {
private static final float[][] COVER_POSITIONS = new float[][]{ new float[] {0.0f, 0.0f},
new float[] {0.4f, 0.0f}, new float[] {0.4f, 0.2f}, new float[] {0.6f, 0.2f}, new float[] {0.8f, 0.2f}};
private final Paint paintTextMain;
@@ -26,14 +26,14 @@ public class FinalShareScreen extends BubbleScreen {
private final Typeface typefaceNormal;
private final Typeface typefaceBold;
- public FinalShareScreen(Context context,
- ArrayList favoritePodNames, ArrayList favoritePodImages) {
+ public FinalShareBackground(Context context,
+ ArrayList favoritePodNames, ArrayList favoritePodImages) {
super(context);
this.heading = context.getString(R.string.echo_share_heading);
this.logo = AppCompatResources.getDrawable(context, R.drawable.echo);
this.favoritePodNames = favoritePodNames;
this.favoritePodImages = favoritePodImages;
- this.year = String.valueOf(EchoActivity.RELEASE_YEAR);
+ this.year = String.valueOf(EchoConfig.RELEASE_YEAR);
typefaceNormal = ResourcesCompat.getFont(context, R.font.sarabun_regular);
typefaceBold = ResourcesCompat.getFont(context, R.font.sarabun_semi_bold);
paintTextMain = new Paint();
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/RotatingSquaresScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/RotatingSquaresBackground.java
similarity index 87%
rename from ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/RotatingSquaresScreen.java
rename to ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/RotatingSquaresBackground.java
index 624b68f88..3901bc5e4 100644
--- a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/RotatingSquaresScreen.java
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/RotatingSquaresBackground.java
@@ -1,11 +1,11 @@
-package de.danoeh.antennapod.ui.echo.screens;
+package de.danoeh.antennapod.ui.echo.background;
import android.content.Context;
import android.graphics.Canvas;
import androidx.annotation.NonNull;
-public class RotatingSquaresScreen extends BaseScreen {
- public RotatingSquaresScreen(Context context) {
+public class RotatingSquaresBackground extends BaseBackground {
+ public RotatingSquaresBackground(Context context) {
super(context);
for (int i = 0; i < 16; i++) {
particles.add(new Particle(
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/StripesScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/StripesBackground.java
similarity index 87%
rename from ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/StripesScreen.java
rename to ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/StripesBackground.java
index 60906776f..5d523335b 100644
--- a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/StripesScreen.java
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/StripesBackground.java
@@ -1,13 +1,13 @@
-package de.danoeh.antennapod.ui.echo.screens;
+package de.danoeh.antennapod.ui.echo.background;
import android.content.Context;
import android.graphics.Canvas;
import androidx.annotation.NonNull;
-public class StripesScreen extends BaseScreen {
+public class StripesBackground extends BaseBackground {
protected static final int NUM_PARTICLES = 15;
- public StripesScreen(Context context) {
+ public StripesBackground(Context context) {
super(context);
for (int i = 0; i < NUM_PARTICLES; i++) {
particles.add(new Particle(2f * i / NUM_PARTICLES - 1f, 0, 0, 0));
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/WaveformScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/WaveformBackground.java
similarity index 89%
rename from ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/WaveformScreen.java
rename to ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/WaveformBackground.java
index d87f7fbb5..419cdf344 100644
--- a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/WaveformScreen.java
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/WaveformBackground.java
@@ -1,13 +1,13 @@
-package de.danoeh.antennapod.ui.echo.screens;
+package de.danoeh.antennapod.ui.echo.background;
import android.content.Context;
import android.graphics.Canvas;
import androidx.annotation.NonNull;
-public class WaveformScreen extends BaseScreen {
+public class WaveformBackground extends BaseBackground {
protected static final int NUM_PARTICLES = 40;
- public WaveformScreen(Context context) {
+ public WaveformBackground(Context context) {
super(context);
for (int i = 0; i < NUM_PARTICLES; i++) {
particles.add(new Particle(1.1f + 1.1f * i / NUM_PARTICLES - 0.05f, 0, 0, 0));
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/WavesScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/WavesBackground.java
similarity index 88%
rename from ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/WavesScreen.java
rename to ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/WavesBackground.java
index eb521f0a2..6ea46853e 100644
--- a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screens/WavesScreen.java
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/background/WavesBackground.java
@@ -1,14 +1,14 @@
-package de.danoeh.antennapod.ui.echo.screens;
+package de.danoeh.antennapod.ui.echo.background;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import androidx.annotation.NonNull;
-public class WavesScreen extends BaseScreen {
+public class WavesBackground extends BaseBackground {
protected static final int NUM_PARTICLES = 10;
- public WavesScreen(Context context) {
+ public WavesBackground(Context context) {
super(context);
paintParticles.setStyle(Paint.Style.STROKE);
for (int i = 0; i < NUM_PARTICLES; i++) {
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/EchoScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/EchoScreen.java
new file mode 100644
index 000000000..9654ca1fc
--- /dev/null
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/EchoScreen.java
@@ -0,0 +1,48 @@
+package de.danoeh.antennapod.ui.echo.screen;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.view.View;
+import androidx.annotation.NonNull;
+import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.ui.echo.R;
+
+import java.util.Locale;
+
+public abstract class EchoScreen {
+ protected final Context context;
+
+ public EchoScreen(Context context) {
+ this.context = context;
+ }
+
+ protected final Locale getEchoLanguage() {
+ boolean hasTranslation = !context.getString(R.string.echo_listened_after_title)
+ .equals(getLocalizedResources(Locale.US).getString(R.string.echo_listened_after_title));
+ if (hasTranslation) {
+ return Locale.getDefault();
+ } else {
+ return Locale.US;
+ }
+ }
+
+ @NonNull
+ protected Resources getLocalizedResources(Locale desiredLocale) {
+ Configuration conf = context.getResources().getConfiguration();
+ conf = new Configuration(conf);
+ conf.setLocale(desiredLocale);
+ Context localizedContext = context.createConfigurationContext(conf);
+ return localizedContext.getResources();
+ }
+
+ public void postInvalidate() {
+ // Do nothing by default
+ }
+
+ public abstract View getView();
+
+ public void startLoading(DBReader.StatisticsResult statisticsResult) {
+ // Do nothing by default
+ }
+}
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/FinalShareScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/FinalShareScreen.java
new file mode 100644
index 000000000..770ca7766
--- /dev/null
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/FinalShareScreen.java
@@ -0,0 +1,127 @@
+package de.danoeh.antennapod.ui.echo.screen;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import androidx.core.app.ShareCompat;
+import androidx.core.content.FileProvider;
+import androidx.core.content.res.ResourcesCompat;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
+import com.bumptech.glide.request.RequestOptions;
+import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
+import de.danoeh.antennapod.ui.echo.EchoConfig;
+import de.danoeh.antennapod.ui.echo.R;
+import de.danoeh.antennapod.ui.echo.background.FinalShareBackground;
+import de.danoeh.antennapod.ui.echo.databinding.SimpleEchoScreenBinding;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+
+public class FinalShareScreen extends EchoScreen {
+ private static final int SHARE_SIZE = 1000;
+ private static final String TAG = "FinalShareScreen";
+ private final SimpleEchoScreenBinding viewBinding;
+ private final ArrayList favoritePodNames = new ArrayList<>();
+ private final ArrayList favoritePodImages = new ArrayList<>();
+ private final FinalShareBackground background;
+ private Disposable disposable;
+
+ public FinalShareScreen(Context context, LayoutInflater layoutInflater) {
+ super(context);
+ viewBinding = SimpleEchoScreenBinding.inflate(layoutInflater);
+ viewBinding.actionButton.setOnClickListener(v -> share());
+ viewBinding.actionButton.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(
+ context.getResources(), R.drawable.ic_share, context.getTheme()), null, null, null);
+ viewBinding.actionButton.setVisibility(View.VISIBLE);
+ viewBinding.actionButton.setText(R.string.share_label);
+ background = new FinalShareBackground(context, favoritePodNames, favoritePodImages);
+ viewBinding.backgroundImage.setImageDrawable(background);
+ }
+
+ @Override
+ public View getView() {
+ return viewBinding.getRoot();
+ }
+
+ @Override
+ public void postInvalidate() {
+ viewBinding.backgroundImage.postInvalidate();
+ }
+
+ private void share() {
+ try {
+ Bitmap bitmap = Bitmap.createBitmap(SHARE_SIZE, SHARE_SIZE, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ background.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ background.draw(canvas);
+ viewBinding.backgroundImage.setImageDrawable(null);
+ viewBinding.backgroundImage.setImageDrawable(background);
+ File file = new File(UserPreferences.getDataFolder(null), "AntennaPodEcho.png");
+ FileOutputStream stream = new FileOutputStream(file);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
+ stream.close();
+
+ Uri fileUri = FileProvider.getUriForFile(context, context.getString(R.string.provider_authority), file);
+ new ShareCompat.IntentBuilder(context)
+ .setType("image/png")
+ .addStream(fileUri)
+ .setText(context.getString(R.string.echo_share, EchoConfig.RELEASE_YEAR))
+ .setChooserTitle(R.string.share_file_label)
+ .startChooser();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void startLoading(DBReader.StatisticsResult statisticsData) {
+ favoritePodNames.clear();
+ for (int i = 0; i < 5 && i < statisticsData.feedTime.size(); i++) {
+ favoritePodNames.add(statisticsData.feedTime.get(i).feed.getTitle());
+ }
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ disposable = Observable.fromCallable(
+ () -> {
+ favoritePodImages.clear();
+ for (int i = 0; i < 5 && i < statisticsData.feedTime.size(); i++) {
+ BitmapDrawable cover = new BitmapDrawable(context.getResources(), (Bitmap) null);
+ try {
+ final int size = SHARE_SIZE / 3;
+ final int radius = (i == 0) ? (size / 16) : (size / 8);
+ cover = new BitmapDrawable(context.getResources(), Glide.with(context)
+ .asBitmap()
+ .load(statisticsData.feedTime.get(i).feed.getImageUrl())
+ .apply(new RequestOptions()
+ .fitCenter()
+ .transform(new RoundedCorners(radius)))
+ .submit(size, size)
+ .get(5, TimeUnit.SECONDS));
+ } catch (Exception e) {
+ Log.d(TAG, "Loading cover: " + e.getMessage());
+ }
+ favoritePodImages.add(cover);
+ }
+ return statisticsData;
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result -> { },
+ error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+}
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/HoarderScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/HoarderScreen.java
new file mode 100644
index 000000000..68ec40fff
--- /dev/null
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/HoarderScreen.java
@@ -0,0 +1,75 @@
+package de.danoeh.antennapod.ui.echo.screen;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.storage.database.StatisticsItem;
+import de.danoeh.antennapod.ui.echo.R;
+import de.danoeh.antennapod.ui.echo.background.WavesBackground;
+import de.danoeh.antennapod.ui.echo.databinding.SimpleEchoScreenBinding;
+
+import java.util.ArrayList;
+
+public class HoarderScreen extends EchoScreen {
+ private final SimpleEchoScreenBinding viewBinding;
+
+ public HoarderScreen(Context context, LayoutInflater layoutInflater) {
+ super(context);
+ viewBinding = SimpleEchoScreenBinding.inflate(layoutInflater);
+ viewBinding.aboveLabel.setText(R.string.echo_hoarder_title);
+ viewBinding.backgroundImage.setImageDrawable(new WavesBackground(context));
+ }
+
+ private void display(int playedActivePodcasts, int totalActivePodcasts, String randomUnplayedActivePodcast) {
+ int percentagePlayed = (int) (100.0 * playedActivePodcasts / totalActivePodcasts);
+ if (percentagePlayed < 25) {
+ viewBinding.largeLabel.setText(R.string.echo_hoarder_emoji_cabinet);
+ viewBinding.belowLabel.setText(R.string.echo_hoarder_subtitle_hoarder);
+ viewBinding.smallLabel.setText(context.getString(R.string.echo_hoarder_comment_hoarder,
+ percentagePlayed, totalActivePodcasts));
+ } else if (percentagePlayed < 75) {
+ viewBinding.largeLabel.setText(R.string.echo_hoarder_emoji_check);
+ viewBinding.belowLabel.setText(R.string.echo_hoarder_subtitle_medium);
+ viewBinding.smallLabel.setText(context.getString(R.string.echo_hoarder_comment_medium,
+ percentagePlayed, totalActivePodcasts, randomUnplayedActivePodcast));
+ } else {
+ viewBinding.largeLabel.setText(R.string.echo_hoarder_emoji_clean);
+ viewBinding.belowLabel.setText(R.string.echo_hoarder_subtitle_clean);
+ viewBinding.smallLabel.setText(context.getString(R.string.echo_hoarder_comment_clean,
+ percentagePlayed, totalActivePodcasts));
+ }
+ }
+
+ @Override
+ public View getView() {
+ return viewBinding.getRoot();
+ }
+
+ @Override
+ public void postInvalidate() {
+ viewBinding.backgroundImage.postInvalidate();
+ }
+
+ @Override
+ public void startLoading(DBReader.StatisticsResult statisticsResult) {
+ int totalActivePodcasts = 0;
+ int playedActivePodcasts = 0;
+ String randomUnplayedActivePodcast = "";
+ ArrayList unplayedActive = new ArrayList<>();
+ for (StatisticsItem item : statisticsResult.feedTime) {
+ if (item.feed.getPreferences().getKeepUpdated()) {
+ totalActivePodcasts++;
+ if (item.timePlayed > 0) {
+ playedActivePodcasts++;
+ } else {
+ unplayedActive.add(item.feed.getTitle());
+ }
+ }
+ }
+ if (!unplayedActive.isEmpty()) {
+ randomUnplayedActivePodcast = unplayedActive.get((int) (Math.random() * unplayedActive.size()));
+ }
+ display(playedActivePodcasts, totalActivePodcasts, randomUnplayedActivePodcast);
+ }
+}
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/HoursPlayedScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/HoursPlayedScreen.java
new file mode 100644
index 000000000..367e21dea
--- /dev/null
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/HoursPlayedScreen.java
@@ -0,0 +1,50 @@
+package de.danoeh.antennapod.ui.echo.screen;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.storage.database.StatisticsItem;
+import de.danoeh.antennapod.ui.echo.R;
+import de.danoeh.antennapod.ui.echo.background.WaveformBackground;
+import de.danoeh.antennapod.ui.echo.databinding.SimpleEchoScreenBinding;
+
+public class HoursPlayedScreen extends EchoScreen {
+ private final SimpleEchoScreenBinding viewBinding;
+
+ public HoursPlayedScreen(Context context, LayoutInflater layoutInflater) {
+ super(context);
+ viewBinding = SimpleEchoScreenBinding.inflate(layoutInflater);
+ viewBinding.aboveLabel.setText(R.string.echo_hours_this_year);
+ viewBinding.backgroundImage.setImageDrawable(new WaveformBackground(context));
+ }
+
+ private void display(long totalTime, int playedPodcasts) {
+ viewBinding.largeLabel.setText(String.format(getEchoLanguage(), "%d", totalTime / 3600));
+ viewBinding.belowLabel.setText(context.getResources()
+ .getQuantityString(R.plurals.echo_hours_podcasts, playedPodcasts, playedPodcasts));
+ }
+
+ @Override
+ public View getView() {
+ return viewBinding.getRoot();
+ }
+
+ @Override
+ public void postInvalidate() {
+ viewBinding.backgroundImage.postInvalidate();
+ }
+
+ @Override
+ public void startLoading(DBReader.StatisticsResult statisticsResult) {
+ int playedPodcasts = 0;
+ long totalTime = 0;
+ for (StatisticsItem item : statisticsResult.feedTime) {
+ totalTime += item.timePlayed;
+ if (item.timePlayed > 0) {
+ playedPodcasts++;
+ }
+ }
+ display(totalTime, playedPodcasts);
+ }
+}
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/IntroScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/IntroScreen.java
new file mode 100644
index 000000000..b9fa5bcda
--- /dev/null
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/IntroScreen.java
@@ -0,0 +1,34 @@
+package de.danoeh.antennapod.ui.echo.screen;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import de.danoeh.antennapod.ui.echo.EchoConfig;
+import de.danoeh.antennapod.ui.echo.R;
+import de.danoeh.antennapod.ui.echo.background.BubbleBackground;
+import de.danoeh.antennapod.ui.echo.databinding.SimpleEchoScreenBinding;
+
+public class IntroScreen extends EchoScreen {
+ private final SimpleEchoScreenBinding viewBinding;
+
+ public IntroScreen(Context context, LayoutInflater layoutInflater) {
+ super(context);
+ viewBinding = SimpleEchoScreenBinding.inflate(layoutInflater);
+ viewBinding.echoLogo.setVisibility(View.VISIBLE);
+ viewBinding.aboveLabel.setText(R.string.echo_intro_your_year);
+ viewBinding.largeLabel.setText(String.format(getEchoLanguage(), "%d", EchoConfig.RELEASE_YEAR));
+ viewBinding.belowLabel.setText(R.string.echo_intro_in_podcasts);
+ viewBinding.smallLabel.setText(R.string.echo_intro_locally);
+ viewBinding.backgroundImage.setImageDrawable(new BubbleBackground(context));
+ }
+
+ @Override
+ public View getView() {
+ return viewBinding.getRoot();
+ }
+
+ @Override
+ public void postInvalidate() {
+ viewBinding.backgroundImage.postInvalidate();
+ }
+}
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/QueueScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/QueueScreen.java
new file mode 100644
index 000000000..4b192997c
--- /dev/null
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/QueueScreen.java
@@ -0,0 +1,97 @@
+package de.danoeh.antennapod.ui.echo.screen;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
+import de.danoeh.antennapod.ui.common.Converter;
+import de.danoeh.antennapod.ui.echo.EchoConfig;
+import de.danoeh.antennapod.ui.echo.R;
+import de.danoeh.antennapod.ui.echo.background.StripesBackground;
+import de.danoeh.antennapod.ui.echo.databinding.SimpleEchoScreenBinding;
+import de.danoeh.antennapod.ui.episodes.PlaybackSpeedUtils;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+import java.util.Calendar;
+
+public class QueueScreen extends EchoScreen {
+ private static final String TAG = "QueueScreen";
+ private final SimpleEchoScreenBinding viewBinding;
+ private Disposable disposable;
+
+ public QueueScreen(Context context, LayoutInflater layoutInflater) {
+ super(context);
+ viewBinding = SimpleEchoScreenBinding.inflate(layoutInflater);
+ viewBinding.backgroundImage.setImageDrawable(new StripesBackground(context));
+ }
+
+ private void display(int queueNumEpisodes, long queueSecondsLeft) {
+ viewBinding.largeLabel.setText(String.format(getEchoLanguage(), "%d", queueSecondsLeft / 3600));
+ viewBinding.belowLabel.setText(context.getResources().getQuantityString(
+ R.plurals.echo_queue_hours_waiting, queueNumEpisodes, queueNumEpisodes));
+
+ Calendar dec31 = Calendar.getInstance();
+ dec31.set(Calendar.DAY_OF_MONTH, 31);
+ dec31.set(Calendar.MONTH, Calendar.DECEMBER);
+ int daysUntilNextYear = Math.max(1,
+ dec31.get(Calendar.DAY_OF_YEAR) - Calendar.getInstance().get(Calendar.DAY_OF_YEAR) + 1);
+ long secondsPerDay = queueSecondsLeft / daysUntilNextYear;
+ String timePerDay = Converter.getDurationStringLocalized(
+ getLocalizedResources(getEchoLanguage()), secondsPerDay * 1000, true);
+ double hoursPerDay = secondsPerDay / 3600.0;
+ int nextYear = EchoConfig.RELEASE_YEAR + 1;
+ if (hoursPerDay < 1.5) {
+ viewBinding.aboveLabel.setText(R.string.echo_queue_title_clean);
+ viewBinding.smallLabel.setText(
+ context.getString(R.string.echo_queue_hours_clean, timePerDay, nextYear));
+ } else if (hoursPerDay <= 24) {
+ viewBinding.aboveLabel.setText(R.string.echo_queue_title_many);
+ viewBinding.smallLabel.setText(
+ context.getString(R.string.echo_queue_hours_normal, timePerDay, nextYear));
+ } else {
+ viewBinding.aboveLabel.setText(R.string.echo_queue_title_many);
+ viewBinding.smallLabel.setText(context.getString(R.string.echo_queue_hours_much, timePerDay, nextYear));
+ }
+ }
+
+ @Override
+ public View getView() {
+ return viewBinding.getRoot();
+ }
+
+ @Override
+ public void postInvalidate() {
+ viewBinding.backgroundImage.postInvalidate();
+ }
+
+ @Override
+ public void startLoading(DBReader.StatisticsResult statisticsResult) {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ disposable = Observable.fromCallable(DBReader::getQueue)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(queue -> {
+ long queueSecondsLeft = 0;
+ for (FeedItem item : queue) {
+ float playbackSpeed = 1;
+ if (UserPreferences.timeRespectsSpeed()) {
+ playbackSpeed = PlaybackSpeedUtils.getCurrentPlaybackSpeed(item.getMedia());
+ }
+ if (item.getMedia() != null) {
+ long itemTimeLeft = item.getMedia().getDuration() - item.getMedia().getPosition();
+ queueSecondsLeft += itemTimeLeft / playbackSpeed;
+ }
+ }
+ queueSecondsLeft /= 1000;
+ display(queue.size(), queueSecondsLeft);
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+}
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/ThanksScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/ThanksScreen.java
new file mode 100644
index 000000000..34f4e9e7e
--- /dev/null
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/ThanksScreen.java
@@ -0,0 +1,50 @@
+package de.danoeh.antennapod.ui.echo.screen;
+
+import android.content.Context;
+import android.text.format.DateFormat;
+import android.view.LayoutInflater;
+import android.view.View;
+import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.ui.echo.EchoConfig;
+import de.danoeh.antennapod.ui.echo.R;
+import de.danoeh.antennapod.ui.echo.background.RotatingSquaresBackground;
+import de.danoeh.antennapod.ui.echo.databinding.SimpleEchoScreenBinding;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class ThanksScreen extends EchoScreen {
+ private final SimpleEchoScreenBinding viewBinding;
+
+ public ThanksScreen(Context context, LayoutInflater layoutInflater) {
+ super(context);
+ viewBinding = SimpleEchoScreenBinding.inflate(layoutInflater);
+ viewBinding.aboveLabel.setText("");
+ viewBinding.largeLabel.setText(R.string.echo_thanks_large);
+
+ viewBinding.smallLabel.setText(R.string.echo_thanks_now_favorite);
+ viewBinding.backgroundImage.setImageDrawable(new RotatingSquaresBackground(context));
+ }
+
+ @Override
+ public View getView() {
+ return viewBinding.getRoot();
+ }
+
+ @Override
+ public void postInvalidate() {
+ viewBinding.backgroundImage.postInvalidate();
+ }
+
+ @Override
+ public void startLoading(DBReader.StatisticsResult statisticsResult) {
+ if (statisticsResult.oldestDate < EchoConfig.jan1()) {
+ String skeleton = DateFormat.getBestDateTimePattern(getEchoLanguage(), "MMMM yyyy");
+ SimpleDateFormat dateFormat = new SimpleDateFormat(skeleton, getEchoLanguage());
+ String dateFrom = dateFormat.format(new Date(statisticsResult.oldestDate));
+ viewBinding.belowLabel.setText(context.getString(R.string.echo_thanks_we_are_glad_old, dateFrom));
+ } else {
+ viewBinding.belowLabel.setText(R.string.echo_thanks_we_are_glad_new);
+ }
+ }
+}
diff --git a/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/TimeReleasePlayScreen.java b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/TimeReleasePlayScreen.java
new file mode 100644
index 000000000..126522782
--- /dev/null
+++ b/ui/echo/src/main/java/de/danoeh/antennapod/ui/echo/screen/TimeReleasePlayScreen.java
@@ -0,0 +1,65 @@
+package de.danoeh.antennapod.ui.echo.screen;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import de.danoeh.antennapod.storage.database.DBReader;
+import de.danoeh.antennapod.ui.common.Converter;
+import de.danoeh.antennapod.ui.echo.EchoConfig;
+import de.danoeh.antennapod.ui.echo.R;
+import de.danoeh.antennapod.ui.echo.background.RotatingSquaresBackground;
+import de.danoeh.antennapod.ui.echo.databinding.SimpleEchoScreenBinding;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+public class TimeReleasePlayScreen extends EchoScreen {
+ private static final String TAG = "TimeReleasePlayScreen";
+ private final SimpleEchoScreenBinding viewBinding;
+ private Disposable disposable;
+
+ public TimeReleasePlayScreen(Context context, LayoutInflater layoutInflater) {
+ super(context);
+ viewBinding = SimpleEchoScreenBinding.inflate(layoutInflater);
+ viewBinding.aboveLabel.setText(R.string.echo_listened_after_title);
+ viewBinding.backgroundImage.setImageDrawable(new RotatingSquaresBackground(context));
+ }
+
+ private void display(long timeBetweenReleaseAndPlay) {
+ if (timeBetweenReleaseAndPlay <= 1000L * 3600 * 24 * 2.5) {
+ viewBinding.largeLabel.setText(R.string.echo_listened_after_emoji_run);
+ viewBinding.belowLabel.setText(R.string.echo_listened_after_comment_addict);
+ } else {
+ viewBinding.largeLabel.setText(R.string.echo_listened_after_emoji_yoga);
+ viewBinding.belowLabel.setText(R.string.echo_listened_after_comment_easy);
+ }
+ viewBinding.smallLabel.setText(context.getString(R.string.echo_listened_after_time,
+ Converter.getDurationStringLocalized(
+ getLocalizedResources(getEchoLanguage()), timeBetweenReleaseAndPlay, true)));
+ }
+
+ @Override
+ public View getView() {
+ return viewBinding.getRoot();
+ }
+
+ @Override
+ public void postInvalidate() {
+ viewBinding.backgroundImage.postInvalidate();
+ }
+
+ @Override
+ public void startLoading(DBReader.StatisticsResult statisticsResult) {
+ super.startLoading(statisticsResult);
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ disposable = Observable.fromCallable(() ->
+ DBReader.getTimeBetweenReleaseAndPlayback(EchoConfig.jan1(), Long.MAX_VALUE))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::display, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+}
diff --git a/ui/echo/src/main/res/layout/echo_activity.xml b/ui/echo/src/main/res/layout/echo_activity.xml
index 3c5590d3a..593d941b6 100644
--- a/ui/echo/src/main/res/layout/echo_activity.xml
+++ b/ui/echo/src/main/res/layout/echo_activity.xml
@@ -1,16 +1,13 @@
-
-
+ android:layout_height="match_parent" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/ui/echo/src/main/res/layout/simple_echo_screen.xml b/ui/echo/src/main/res/layout/simple_echo_screen.xml
new file mode 100644
index 000000000..c151682eb
--- /dev/null
+++ b/ui/echo/src/main/res/layout/simple_echo_screen.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/echo/src/main/res/values/echo-strings.xml b/ui/echo/src/main/res/values/echo-strings.xml
index 09a64f1e4..161fe363e 100644
--- a/ui/echo/src/main/res/values/echo-strings.xml
+++ b/ui/echo/src/main/res/values/echo-strings.xml
@@ -1,5 +1,6 @@
+ [Debug] Echo
Review the year
Your top podcasts and stats from the past year. Exclusively on your phone.
diff --git a/ui/statistics/build.gradle b/ui/statistics/build.gradle
index e5e00d32d..1e33a0f0a 100644
--- a/ui/statistics/build.gradle
+++ b/ui/statistics/build.gradle
@@ -15,6 +15,7 @@ dependencies {
implementation project(':storage:database')
implementation project(":ui:app-start-intent")
implementation project(":ui:common")
+ implementation project(":ui:echo")
annotationProcessor "androidx.annotation:annotation:$annotationVersion"
implementation "androidx.appcompat:appcompat:$appcompatVersion"
diff --git a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/StatisticsFragment.java b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/StatisticsFragment.java
index 6dfdc4e8a..1c35b159b 100644
--- a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/StatisticsFragment.java
+++ b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/StatisticsFragment.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.ui.statistics;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -21,6 +22,7 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.event.StatisticsEvent;
import de.danoeh.antennapod.ui.common.PagedToolbarFragment;
+import de.danoeh.antennapod.ui.echo.EchoActivity;
import de.danoeh.antennapod.ui.statistics.downloads.DownloadStatisticsFragment;
import de.danoeh.antennapod.ui.statistics.subscriptions.SubscriptionStatisticsFragment;
import de.danoeh.antennapod.ui.statistics.years.YearsStatisticsFragment;
@@ -61,6 +63,9 @@ public class StatisticsFragment extends PagedToolbarFragment {
toolbar = rootView.findViewById(R.id.toolbar);
toolbar.setTitle(getString(R.string.statistics_label));
toolbar.inflateMenu(R.menu.statistics);
+ if (BuildConfig.DEBUG) {
+ toolbar.getMenu().findItem(R.id.debug_echo).setVisible(true);
+ }
toolbar.setNavigationOnClickListener(v -> getParentFragmentManager().popBackStack());
viewPager.setAdapter(new StatisticsPagerAdapter(this));
// Give the TabLayout the ViewPager
@@ -89,6 +94,8 @@ public class StatisticsFragment extends PagedToolbarFragment {
if (item.getItemId() == R.id.statistics_reset) {
confirmResetStatistics();
return true;
+ } else if (item.getItemId() == R.id.debug_echo) {
+ startActivity(new Intent(getContext(), EchoActivity.class));
}
return super.onOptionsItemSelected(item);
}
diff --git a/ui/statistics/src/main/res/menu/statistics.xml b/ui/statistics/src/main/res/menu/statistics.xml
index 4610a7726..9720e6880 100644
--- a/ui/statistics/src/main/res/menu/statistics.xml
+++ b/ui/statistics/src/main/res/menu/statistics.xml
@@ -11,7 +11,12 @@
android:id="@+id/statistics_filter"
android:icon="@drawable/ic_filter"
android:title="@string/filter"
- custom:showAsAction="ifRoom">
-
+ custom:showAsAction="ifRoom" />
+
+