Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fcbe4377aa | ||
|
|
84db4060e6 | ||
|
|
b73a1c532b | ||
|
|
4fe27067e9 | ||
|
|
9c6981ed19 | ||
|
|
560ac2df68 | ||
|
|
260e6e9daa | ||
|
|
38a1368c76 | ||
|
|
9bf3139bd2 | ||
|
|
d389d1d62a | ||
|
|
e60c0e312c |
@@ -28,8 +28,8 @@ android {
|
||||
tempo {
|
||||
dimension "default"
|
||||
applicationId 'com.cappielloantonio.tempo'
|
||||
versionCode 12
|
||||
versionName '3.4.5'
|
||||
versionCode 14
|
||||
versionName '3.4.7'
|
||||
}
|
||||
|
||||
notquitemy {
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface RecentSearchDao {
|
||||
@Query("SELECT * FROM recent_search ORDER BY search ASC")
|
||||
@Query("SELECT * FROM recent_search ORDER BY search DESC")
|
||||
List<String> getRecent();
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
|
||||
@@ -24,9 +24,14 @@ public class GenreRepository {
|
||||
.enqueue(new Callback<ApiResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
|
||||
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getGenres() != null) {
|
||||
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse() != null && response.body().getSubsonicResponse().getGenres() != null) {
|
||||
List<Genre> genreList = response.body().getSubsonicResponse().getGenres().getGenres();
|
||||
|
||||
if (genreList == null || genreList.isEmpty()) {
|
||||
genres.setValue(Collections.emptyList());
|
||||
return;
|
||||
}
|
||||
|
||||
if (random) {
|
||||
Collections.shuffle(genreList);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.cappielloantonio.tempo.repository;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
@@ -100,6 +102,8 @@ public class SearchingRepository {
|
||||
LinkedHashSet<String> hashSet = new LinkedHashSet<>(newSuggestions);
|
||||
ArrayList<String> suggestionsWithoutDuplicates = new ArrayList<>(hashSet);
|
||||
|
||||
Log.d("suggestionsWithoutDuplicates", suggestionsWithoutDuplicates.toString());
|
||||
|
||||
suggestions.setValue(suggestionsWithoutDuplicates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter<SongHorizontalAd
|
||||
}
|
||||
|
||||
public void setItems(List<Child> songs) {
|
||||
this.songs = songs;
|
||||
this.songs = songs != null ? songs : Collections.emptyList();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -51,6 +52,7 @@ public class PlayerControllerFragment extends Fragment {
|
||||
private Chip playerMediaExtension;
|
||||
private TextView playerMediaBitrate;
|
||||
private ImageView playerMediaTranscodingIcon;
|
||||
private ImageView playerMediaTranscodingPriorityIcon;
|
||||
private Chip playerMediaTranscodedExtension;
|
||||
private TextView playerMediaTranscodedBitrate;
|
||||
|
||||
@@ -71,6 +73,7 @@ public class PlayerControllerFragment extends Fragment {
|
||||
initCoverLyricsSlideView();
|
||||
initMediaListenable();
|
||||
initArtistLabelButton();
|
||||
initTranscodingInfo();
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -104,6 +107,7 @@ public class PlayerControllerFragment extends Fragment {
|
||||
playerMediaExtension = bind.getRoot().findViewById(R.id.player_media_extension);
|
||||
playerMediaBitrate = bind.getRoot().findViewById(R.id.player_media_bitrate);
|
||||
playerMediaTranscodingIcon = bind.getRoot().findViewById(R.id.player_media_transcoding_audio);
|
||||
playerMediaTranscodingPriorityIcon = bind.getRoot().findViewById(R.id.player_media_server_transcode_priority);
|
||||
playerMediaTranscodedExtension = bind.getRoot().findViewById(R.id.player_media_transcoded_extension);
|
||||
playerMediaTranscodedBitrate = bind.getRoot().findViewById(R.id.player_media_transcoded_bitrate);
|
||||
}
|
||||
@@ -166,7 +170,6 @@ public class PlayerControllerFragment extends Fragment {
|
||||
playerMediaBitrate.setVisibility(View.GONE);
|
||||
} else {
|
||||
playerMediaBitrate.setVisibility(View.VISIBLE);
|
||||
|
||||
playerMediaBitrate.setText(bitrate);
|
||||
}
|
||||
}
|
||||
@@ -177,19 +180,28 @@ public class PlayerControllerFragment extends Fragment {
|
||||
: "Original";
|
||||
|
||||
if (transcodingExtension.equals("raw") && transcodingBitrate.equals("Original")) {
|
||||
playerMediaTranscodingPriorityIcon.setVisibility(View.GONE);
|
||||
playerMediaTranscodingIcon.setVisibility(View.GONE);
|
||||
playerMediaTranscodedBitrate.setVisibility(View.GONE);
|
||||
playerMediaTranscodedExtension.setVisibility(View.GONE);
|
||||
} else {
|
||||
playerMediaTranscodingPriorityIcon.setVisibility(View.GONE);
|
||||
playerMediaTranscodingIcon.setVisibility(View.VISIBLE);
|
||||
playerMediaTranscodedBitrate.setVisibility(View.VISIBLE);
|
||||
playerMediaTranscodedExtension.setVisibility(View.VISIBLE);
|
||||
|
||||
playerMediaTranscodedExtension.setText(transcodingExtension);
|
||||
playerMediaTranscodedBitrate.setText(transcodingBitrate);
|
||||
}
|
||||
|
||||
if (mediaMetadata.extras != null && mediaMetadata.extras.getString("uri", "").contains(Constants.DOWNLOAD_URI)) {
|
||||
playerMediaTranscodingPriorityIcon.setVisibility(View.GONE);
|
||||
playerMediaTranscodingIcon.setVisibility(View.GONE);
|
||||
playerMediaTranscodedBitrate.setVisibility(View.GONE);
|
||||
playerMediaTranscodedExtension.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (Preferences.isServerPrioritized() && mediaMetadata.extras != null && !mediaMetadata.extras.getString("uri", "").contains(Constants.DOWNLOAD_URI)) {
|
||||
playerMediaTranscodingPriorityIcon.setVisibility(View.VISIBLE);
|
||||
playerMediaTranscodingIcon.setVisibility(View.GONE);
|
||||
playerMediaTranscodedBitrate.setVisibility(View.GONE);
|
||||
playerMediaTranscodedExtension.setVisibility(View.GONE);
|
||||
@@ -293,6 +305,13 @@ public class PlayerControllerFragment extends Fragment {
|
||||
});
|
||||
}
|
||||
|
||||
private void initTranscodingInfo() {
|
||||
playerMediaTranscodingPriorityIcon.setOnLongClickListener(view -> {
|
||||
Toast.makeText(requireActivity(), R.string.settings_audio_transcode_priority_toast, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void initPlaybackSpeedButton(MediaBrowser mediaBrowser) {
|
||||
playbackSpeedButton.setOnClickListener(view -> {
|
||||
float currentSpeed = Preferences.getPlaybackSpeed();
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.ComponentName;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -121,17 +122,11 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
||||
bind.searchView
|
||||
.getEditText()
|
||||
.setOnEditorActionListener((textView, actionId, keyEvent) -> {
|
||||
|
||||
String query = bind.searchView.getText().toString();
|
||||
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
if (isQueryValid(query)) {
|
||||
search(bind.searchView.getText().toString());
|
||||
return true;
|
||||
} else {
|
||||
Toast.makeText(requireContext(), getString(R.string.search_info_minimum_characters), Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
if (isQueryValid(query)) {
|
||||
search(query);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -147,7 +142,7 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
|
||||
if (count > 1) {
|
||||
if (start + count > 1) {
|
||||
setSearchSuggestions(charSequence.toString());
|
||||
} else {
|
||||
setRecentSuggestions();
|
||||
@@ -247,6 +242,7 @@ public class SearchFragment extends Fragment implements ClickCallback {
|
||||
}
|
||||
|
||||
private boolean isQueryValid(String query) {
|
||||
Log.d(TAG, "isQueryValid()");
|
||||
return !query.equals("") && query.trim().length() > 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.annotation.OptIn;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import com.cappielloantonio.tempo.BuildConfig;
|
||||
@@ -70,6 +71,8 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
checkEqualizer();
|
||||
|
||||
findPreference("version").setSummary(BuildConfig.VERSION_NAME);
|
||||
|
||||
findPreference("logout").setOnPreferenceClickListener(preference -> {
|
||||
@@ -93,12 +96,6 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("equalizer").setOnPreferenceClickListener(preference -> {
|
||||
Intent intent = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
|
||||
someActivityResultLauncher.launch(intent);
|
||||
return true;
|
||||
});
|
||||
|
||||
findPreference("sync_starred_tracks_for_offline_use").setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
if ((Boolean) newValue) {
|
||||
@@ -130,6 +127,23 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEqualizer() {
|
||||
Preference equalizer = findPreference("equalizer");
|
||||
|
||||
if (equalizer == null) return;
|
||||
|
||||
Intent intent = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
|
||||
|
||||
if ((intent.resolveActivity(requireActivity().getPackageManager()) != null)) {
|
||||
equalizer.setOnPreferenceClickListener(preference -> {
|
||||
someActivityResultLauncher.launch(intent);
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
equalizer.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void getScanStatus() {
|
||||
settingViewModel.getScanStatus(new ScanCallback() {
|
||||
@Override
|
||||
|
||||
@@ -41,8 +41,11 @@ public class MusicUtil {
|
||||
if (params.containsKey("c") && params.get("c") != null)
|
||||
uri.append("&c=").append(params.get("c"));
|
||||
|
||||
uri.append("&maxBitRate=").append(getBitratePreference());
|
||||
uri.append("&format=").append(getTranscodingFormatPreference());
|
||||
if (!Preferences.isServerPrioritized())
|
||||
uri.append("&maxBitRate=").append(getBitratePreference());
|
||||
if (!Preferences.isServerPrioritized())
|
||||
uri.append("&format=").append(getTranscodingFormatPreference());
|
||||
|
||||
uri.append("&id=").append(id);
|
||||
|
||||
Log.d(TAG, "getStreamUri: " + uri);
|
||||
|
||||
@@ -32,6 +32,7 @@ object Preferences {
|
||||
private const val RADIO_SECTION_VISIBILITY = "radio_section_visibility"
|
||||
private const val MUSIC_DIRECTORY_SECTION_VISIBILITY = "music_directory_section_visibility"
|
||||
private const val REPLAY_GAIN_MODE = "replay_gain_mode"
|
||||
private const val AUDIO_TRANSCODE_PRIORITY = "audio_transcode_priority"
|
||||
|
||||
@JvmStatic
|
||||
fun getServer(): String? {
|
||||
@@ -252,4 +253,9 @@ object Preferences {
|
||||
fun getReplayGainMode(): String? {
|
||||
return App.getInstance().preferences.getString(REPLAY_GAIN_MODE, "disabled")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isServerPrioritized(): Boolean {
|
||||
return App.getInstance().preferences.getBoolean(AUDIO_TRANSCODE_PRIORITY, false)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@color/titleTextColor"
|
||||
android:pathData="M480,796.92Q455.25,796.92 437.63,779.29Q420,761.67 420,736.92Q420,712.17 437.63,694.55Q455.25,676.92 480,676.92Q504.75,676.92 522.37,694.55Q540,712.17 540,736.92Q540,761.67 522.37,779.29Q504.75,796.92 480,796.92ZM425.39,600.77L425.39,143.08L534.61,143.08L534.61,600.77L425.39,600.77Z"/>
|
||||
</vector>
|
||||
@@ -41,6 +41,13 @@
|
||||
android:src="@drawable/ic_transcode"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/player_media_server_transcode_priority"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="20dp"
|
||||
android:src="@drawable/ic_server_transcode_priority"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/player_media_transcoded_extension"
|
||||
style="@style/Widget.Material3.Chip.Suggestion"
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/search_suggestion_delete_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_close"
|
||||
app:layout_constraintBottom_toBottomOf="@id/search_suggestion_icon"
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
<string name="menu_search_button">Search</string>
|
||||
<string name="menu_settings_button">Settings</string>
|
||||
<string name="player_playback_speed">%1$.2fx</string>
|
||||
<string name="player_server_priority">Server Priority</string>
|
||||
<string name="playlist_catalogue_title">Playlist Catalogue</string>
|
||||
<string name="playlist_catalogue_title_expanded">Browse Playlists</string>
|
||||
<string name="playlist_chooser_dialog_empty">No playlists created</string>
|
||||
@@ -170,10 +171,13 @@
|
||||
<string name="server_unreachable_dialog_summary">The requested server is unavailable. If you choose to continue this dialog will not appear for the next hour.</string>
|
||||
<string name="settings_about_summary">Tempo is an open source and lightweight music client for Subsonic, designed and built natively for Android.</string>
|
||||
<string name="settings_about_title">About</string>
|
||||
<string name="settings_audio_transcode_priority_summary">If enabled, Tempo will not force stream the track with the transcode settings below.</string>
|
||||
<string name="settings_audio_transcode_priority_title">Prioritize server transcode settings</string>
|
||||
<string name="settings_audio_transcode_priority_toast">Priority on transcoding of track given to server</string>
|
||||
<string name="settings_audio_transcode_format_mobile">Transcode format in mobile</string>
|
||||
<string name="settings_audio_transcode_format_wifi">Transcode format in Wi-Fi</string>
|
||||
<string name="settings_covers_cache">Size of artwork cache</string>
|
||||
<string name="settings_data_saving_mode_summary">In order to reduce data consumption, avoid downloading covers</string>
|
||||
<string name="settings_data_saving_mode_summary">In order to reduce data consumption, avoid downloading covers.</string>
|
||||
<string name="settings_data_saving_mode_title">Limit mobile data usage</string>
|
||||
<string name="settings_equalizer_summary">Adjust audio settings</string>
|
||||
<string name="settings_equalizer_title">Equalizer</string>
|
||||
@@ -242,7 +246,7 @@
|
||||
<string name="starred_sync_dialog_title">Sync starred tracks</string>
|
||||
<string name="undraw_url">https://undraw.co/</string>
|
||||
<string name="undraw_page">unDraw</string>
|
||||
<string name="undraw_thanks">A special thanks goes to unDraw without whose illustrations we could not have made this application more beautiful</string>
|
||||
<string name="undraw_thanks">A special thanks goes to unDraw without whose illustrations we could not have made this application more beautiful.</string>
|
||||
<string name="home_title_radio_station">Radio stations</string>
|
||||
<string name="home_title_new_releases">New releases</string>
|
||||
<string name="home_title_best_of">Best of</string>
|
||||
@@ -261,6 +265,4 @@
|
||||
<string name="menu_sort_name">Name</string>
|
||||
<string name="menu_sort_random">Random</string>
|
||||
<string name="description_empty_title">No description available</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
</resources>
|
||||
@@ -102,6 +102,12 @@
|
||||
app:selectable="false"
|
||||
app:summary="@string/settings_summary_transcoding" />
|
||||
|
||||
<SwitchPreference
|
||||
android:title="@string/settings_audio_transcode_priority_title"
|
||||
android:defaultValue="false"
|
||||
android:summary="@string/settings_audio_transcode_priority_summary"
|
||||
android:key="audio_transcode_priority" />
|
||||
|
||||
<ListPreference
|
||||
app:defaultValue="raw"
|
||||
app:dialogTitle="@string/settings_audio_transcode_format_wifi"
|
||||
|
||||
225
app/src/notquitemy/res/drawable/ic_splash_logo.xml
Normal file
201
app/src/notquitemy/res/drawable/ic_toolbar_tempo.xml
Normal file
6
app/src/notquitemy/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
|
||||
</adaptive-icon>
|
||||
BIN
app/src/notquitemy/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
app/src/notquitemy/res/mipmap-hdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 857 B |
BIN
app/src/notquitemy/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
app/src/notquitemy/res/mipmap-hdpi/ic_launcher_monochrome.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
app/src/notquitemy/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
app/src/notquitemy/res/mipmap-mdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 463 B |
BIN
app/src/notquitemy/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
app/src/notquitemy/res/mipmap-mdpi/ic_launcher_monochrome.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
app/src/notquitemy/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
app/src/notquitemy/res/mipmap-xhdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/notquitemy/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/src/notquitemy/res/mipmap-xhdpi/ic_launcher_monochrome.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/src/notquitemy/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
app/src/notquitemy/res/mipmap-xxhdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/notquitemy/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
app/src/notquitemy/res/mipmap-xxhdpi/ic_launcher_monochrome.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
app/src/notquitemy/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
app/src/notquitemy/res/mipmap-xxxhdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
app/src/notquitemy/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
app/src/notquitemy/res/mipmap-xxxhdpi/ic_launcher_monochrome.png
Normal file
|
After Width: | Height: | Size: 31 KiB |