Merge pull request #600 from ultrasonic/permission_failed

Migrate Permission utitlity to Kotlin, increase min SDK to 17
This commit is contained in:
Nite 2021-10-14 21:35:51 +02:00 committed by GitHub
commit 784c65f96d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 625 additions and 2575 deletions

View File

@ -1,5 +1,5 @@
ext.versions = [
minSdk : 14,
minSdk : 17,
targetSdk : 29,
compileSdk : 29,
// You need to run ./gradlew wrapper after updating the version

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,9 @@
android:theme="@style/NoActionBar"
android:name=".app.UApp"
android:label="@string/common.appname"
android:usesCleartextTraffic="true">
android:usesCleartextTraffic="true"
android:supportsRtl="false"
tools:ignore="UnusedAttribute">
<meta-data android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>

View File

@ -144,7 +144,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
setupServersCategory();
sharingDefaultGreeting.setText(Settings.getShareGreeting());
setupClearSearchPreference();
setupGaplessControlSettingsV14();
setupFeatureFlagsPreferences();
setupCacheLocationPreference();
setupBluetoothDevicePreferences();
@ -224,8 +223,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
}
private void setupCacheLocationPreference() {
cacheLocation.setSummary(settings.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION,
FileUtil.getDefaultMusicDirectory().getPath()));
cacheLocation.setSummary(Settings.getCacheLocation());
cacheLocation.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
@ -376,24 +374,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
}
private void setupGaplessControlSettingsV14() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
PreferenceCategory playbackControlSettings =
findPreference(Constants.PREFERENCES_KEY_PLAYBACK_CONTROL_SETTINGS);
CheckBoxPreference gaplessPlaybackEnabled =
findPreference(Constants.PREFERENCES_KEY_GAPLESS_PLAYBACK);
if (gaplessPlaybackEnabled != null) {
gaplessPlaybackEnabled.setChecked(false);
gaplessPlaybackEnabled.setEnabled(false);
if (playbackControlSettings != null) {
playbackControlSettings.removePreference(gaplessPlaybackEnabled);
}
}
}
}
private void setupServersCategory() {
addServerPreference.setPersistent(false);
addServerPreference.setTitle(getResources().getString(R.string.settings_server_manage_servers));
@ -431,8 +411,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
sharingDefaultExpiration.setSummary(sharingDefaultExpiration.getText());
sharingDefaultDescription.setSummary(sharingDefaultDescription.getText());
sharingDefaultGreeting.setSummary(sharingDefaultGreeting.getText());
cacheLocation.setSummary(settings.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION,
FileUtil.getDefaultMusicDirectory().getPath()));
cacheLocation.setSummary(Settings.getCacheLocation());
if (!mediaButtonsEnabled.isChecked()) {
lockScreenEnabled.setChecked(false);

View File

@ -1,237 +0,0 @@
package org.moire.ultrasonic.util;
import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.PermissionChecker;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.DexterError;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.PermissionRequestErrorListener;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import org.moire.ultrasonic.R;
import java.util.List;
import timber.log.Timber;
import static androidx.core.content.PermissionChecker.PERMISSION_DENIED;
/**
* Contains static functions for Permission handling
*/
public class PermissionUtil {
private Context activityContext;
private final Context applicationContext;
public PermissionUtil(Context context) {
applicationContext = context;
}
public interface PermissionRequestFinishedCallback {
void onPermissionRequestFinished(boolean hasPermission);
}
public void ForegroundApplicationStarted(Context context) {
this.activityContext = context;
}
public void ForegroundApplicationStopped() {
activityContext = null;
}
/**
* This function can be used to handle file access permission failures.
*
* It will check if the failure is because the necessary permissions aren't available,
* and it will request them, if necessary.
*
* @param callback callback function to execute after the permission request is finished
*/
public void handlePermissionFailed(@Nullable final PermissionRequestFinishedCallback callback) {
String currentCachePath = Settings.getPreferences().getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
String defaultCachePath = FileUtil.getDefaultMusicDirectory().getPath();
// Ultrasonic can do nothing about this error when the Music Directory is already set to the default.
if (currentCachePath.compareTo(defaultCachePath) == 0) return;
if ((PermissionChecker.checkSelfPermission(applicationContext, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PERMISSION_DENIED) ||
(PermissionChecker.checkSelfPermission(applicationContext, Manifest.permission.READ_EXTERNAL_STORAGE) == PERMISSION_DENIED)) {
// While we request permission, the Music Directory is temporarily reset to its default location
setCacheLocation(applicationContext, FileUtil.getDefaultMusicDirectory().getPath());
// If the application is not running, we can't notify the user
if (activityContext == null) return;
requestFailedPermission(activityContext, currentCachePath, callback);
} else {
setCacheLocation(applicationContext, FileUtil.getDefaultMusicDirectory().getPath());
// If the application is not running, we can't notify the user
if (activityContext != null) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
showWarning(activityContext, activityContext.getString(R.string.permissions_message_box_title), activityContext.getString(R.string.permissions_access_error), null);
}
});
}
if (callback != null) {
callback.onPermissionRequestFinished(false);
}
}
}
/**
* This function requests permission to access the filesystem.
* It can be used to request the permission initially, e.g. when the user decides to use a non-default folder for the cache
* @param context context for the operation
* @param callback callback function to execute after the permission request is finished
*/
public static void requestInitialPermission(final Context context, final PermissionRequestFinishedCallback callback) {
Dexter.withContext(context)
.withPermissions(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new MultiplePermissionsListener() {
@Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
Timber.i("Permission granted to read / write external storage");
if (callback != null) callback.onPermissionRequestFinished(true);
return;
}
if (report.isAnyPermissionPermanentlyDenied()) {
Timber.i("Found permanently denied permission to read / write external storage, offering settings");
showSettingsDialog(context);
if (callback != null) callback.onPermissionRequestFinished(false);
return;
}
Timber.i("At least one permission is missing to read / write external storage");
showWarning(context, context.getString(R.string.permissions_message_box_title),
context.getString(R.string.permissions_rationale_description_initial), null);
if (callback != null) callback.onPermissionRequestFinished(false);
}
@Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
showWarning(context, context.getString(R.string.permissions_rationale_title),
context.getString(R.string.permissions_rationale_description_initial), token);
}
}).withErrorListener(new PermissionRequestErrorListener() {
@Override
public void onError(DexterError error) {
Timber.e("An error has occurred during checking permissions with Dexter: %s", error.toString());
}
})
.check();
}
private static void setCacheLocation(Context context, String cacheLocation) {
Settings.getPreferences().edit()
.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, cacheLocation)
.apply();
}
private static void requestFailedPermission(final Context context, final String cacheLocation, final PermissionRequestFinishedCallback callback) {
Dexter.withContext(context)
.withPermissions(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new MultiplePermissionsListener() {
@Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
Timber.i("Permission granted to use cache directory %s", cacheLocation);
setCacheLocation(context, cacheLocation);
if (callback != null) callback.onPermissionRequestFinished(true);
return;
}
if (report.isAnyPermissionPermanentlyDenied()) {
Timber.i("Found permanently denied permission to use cache directory %s, offering settings", cacheLocation);
showSettingsDialog(context);
if (callback != null) callback.onPermissionRequestFinished(false);
return;
}
Timber.i("At least one permission is missing to use directory %s ", cacheLocation);
setCacheLocation(context, FileUtil.getDefaultMusicDirectory().getPath());
showWarning(context, context.getString(R.string.permissions_message_box_title),
context.getString(R.string.permissions_permission_missing), null);
if (callback != null) callback.onPermissionRequestFinished(false);
}
@Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
showWarning(context, context.getString(R.string.permissions_rationale_title),
context.getString(R.string.permissions_rationale_description_failed), token);
}
}).withErrorListener(new PermissionRequestErrorListener() {
@Override
public void onError(DexterError error) {
Timber.e("An error has occurred during checking permissions with Dexter: %s", error.toString());
}
})
.check();
}
private static void showSettingsDialog(final Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.Theme_AppCompat_Dialog);
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setTitle(context.getString(R.string.permissions_permanent_denial_title));
builder.setMessage(context.getString(R.string.permissions_permanent_denial_description));
builder.setPositiveButton(context.getString(R.string.permissions_open_settings), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
openSettings(context);
}
});
builder.setNegativeButton(context.getString(R.string.common_cancel), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setCacheLocation(context, FileUtil.getDefaultMusicDirectory().getPath());
dialog.cancel();
}
});
builder.show();
}
private static void openSettings(Context context) {
Intent i = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:" + context.getPackageName()));
context.startActivity(i);
}
private static void showWarning(Context context, String title, String text, final PermissionToken token) {
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.Theme_AppCompat_Dialog);
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setTitle(title);
builder.setMessage(text);
builder.setPositiveButton(context.getString(R.string.common_ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
if (token != null) token.continuePermissionRequest();
}
});
builder.show();
}
}

View File

@ -83,7 +83,7 @@ class NavigationActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
setUncaughtExceptionHandler()
permissionUtil.ForegroundApplicationStarted(this)
permissionUtil.onForegroundApplicationStarted(this)
Util.applyTheme(this)
super.onCreate(savedInstanceState)
@ -198,7 +198,7 @@ class NavigationActivity : AppCompatActivity() {
nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener)
themeChangedEventDistributor.unsubscribe(themeChangedEventListener)
imageLoaderProvider.clearImageLoader()
permissionUtil.ForegroundApplicationStopped()
permissionUtil.onForegroundApplicationStopped()
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
@ -304,12 +304,7 @@ class NavigationActivity : AppCompatActivity() {
PreferenceManager.setDefaultValues(this, R.xml.settings, false)
val preferences = Settings.preferences
if (!preferences.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) {
val editor = preferences.edit()
editor.putString(
Constants.PREFERENCES_KEY_CACHE_LOCATION,
FileUtil.defaultMusicDirectory.path
)
editor.apply()
Settings.cacheLocation = FileUtil.defaultMusicDirectory.path
}
}

View File

@ -415,10 +415,9 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
}
Util.showDialog(
activity,
android.R.drawable.ic_dialog_info,
R.string.settings_testing_ok,
dialogText
context = requireActivity(),
titleId = R.string.settings_testing_ok,
message = dialogText
)
}

View File

@ -485,11 +485,7 @@ class LocalMediaPlayer : KoinComponent {
try {
setNextPlayerState(PlayerState.PREPARED)
if (Settings.gaplessPlayback &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN &&
(
playerState === PlayerState.STARTED ||
playerState === PlayerState.PAUSED
)
(playerState === PlayerState.STARTED || playerState === PlayerState.PAUSED)
) {
mediaPlayer.setNextMediaPlayer(nextMediaPlayer)
nextSetup = true

View File

@ -253,9 +253,8 @@ object FileUtil {
@JvmStatic
val musicDirectory: File
get() {
val path = Settings.preferences
.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, defaultMusicDirectory.path)
val dir = File(path!!)
val path = Settings.cacheLocation
val dir = File(path)
val hasAccess = ensureDirectoryExistsAndIsReadWritable(dir)
if (!hasAccess) permissionUtil.value.handlePermissionFailed(null)
return if (hasAccess) dir else defaultMusicDirectory

View File

@ -0,0 +1,259 @@
package org.moire.ultrasonic.util
import android.Manifest
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Handler
import android.os.Looper
import androidx.core.content.PermissionChecker
import com.karumi.dexter.Dexter
import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import org.moire.ultrasonic.R
import org.moire.ultrasonic.util.FileUtil.defaultMusicDirectory
import timber.log.Timber
/**
* Contains static functions for Permission handling
*/
class PermissionUtil(private val applicationContext: Context) {
private var activityContext: Context? = null
interface PermissionRequestFinishedCallback {
fun onPermissionRequestFinished(hasPermission: Boolean)
}
fun onForegroundApplicationStarted(context: Context?) {
activityContext = context
}
fun onForegroundApplicationStopped() {
activityContext = null
}
/**
* This function can be used to handle file access permission failures.
*
* It will check if the failure is because the necessary permissions aren't available,
* and it will request them, if necessary.
*
* @param callback callback function to execute after the permission request is finished
*/
fun handlePermissionFailed(callback: PermissionRequestFinishedCallback?) {
val currentCachePath = Settings.cacheLocation
val defaultCachePath = defaultMusicDirectory.path
// Ultrasonic can do nothing about this error when the Music Directory is already set to the default.
if (currentCachePath.compareTo(defaultCachePath) == 0) return
if (PermissionChecker.checkSelfPermission(
applicationContext,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PermissionChecker.PERMISSION_DENIED ||
PermissionChecker.checkSelfPermission(
applicationContext,
Manifest.permission.READ_EXTERNAL_STORAGE
) == PermissionChecker.PERMISSION_DENIED
) {
// While we request permission, the Music Directory is temporarily reset to its default location
Settings.cacheLocation = defaultMusicDirectory.path
// If the application is not running, we can't notify the user
if (activityContext == null) return
requestFailedPermission(activityContext!!, currentCachePath, callback)
} else {
Settings.cacheLocation = defaultMusicDirectory.path
// If the application is not running, we can't notify the user
if (activityContext != null) {
Handler(Looper.getMainLooper()).post {
showWarning(
activityContext!!,
activityContext!!.getString(R.string.permissions_message_box_title),
activityContext!!.getString(R.string.permissions_access_error),
null
)
}
}
callback?.onPermissionRequestFinished(false)
}
}
companion object {
/**
* This function requests permission to access the filesystem.
* It can be used to request the permission initially, e.g. when the user decides to
* use a non-default folder for the cache
* @param context context for the operation
* @param callback callback function to execute after the permission request is finished
*/
@JvmStatic
fun requestInitialPermission(
context: Context,
callback: PermissionRequestFinishedCallback?
) {
Dexter.withContext(context)
.withPermissions(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
.withListener(object : MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport) {
if (report.areAllPermissionsGranted()) {
Timber.i("R/W permission granted for external storage")
callback?.onPermissionRequestFinished(true)
return
}
if (report.isAnyPermissionPermanentlyDenied) {
Timber.i(
"R/W permission is permanently denied for external storage"
)
showSettingsDialog(context)
callback?.onPermissionRequestFinished(false)
return
}
Timber.i("R/W permission is missing for external storage")
showWarning(
context,
context.getString(R.string.permissions_message_box_title),
context.getString(R.string.permissions_rationale_description_initial),
null
)
callback?.onPermissionRequestFinished(false)
}
override fun onPermissionRationaleShouldBeShown(
permissions: List<PermissionRequest>,
token: PermissionToken
) {
showWarning(
context,
context.getString(R.string.permissions_rationale_title),
context.getString(R.string.permissions_rationale_description_initial),
token
)
}
}).withErrorListener { error ->
Timber.e(
"An error has occurred during checking permissions with Dexter: %s",
error.toString()
)
}
.check()
}
private fun requestFailedPermission(
context: Context,
cacheLocation: String?,
callback: PermissionRequestFinishedCallback?
) {
Dexter.withContext(context)
.withPermissions(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
.withListener(object : MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport) {
if (report.areAllPermissionsGranted()) {
Timber.i("Permission granted to use cache directory %s", cacheLocation)
if (cacheLocation != null) {
Settings.cacheLocation = cacheLocation
}
callback?.onPermissionRequestFinished(true)
return
}
if (report.isAnyPermissionPermanentlyDenied) {
Timber.i(
"R/W permission for cache directory %s was permanently denied",
cacheLocation
)
showSettingsDialog(context)
callback?.onPermissionRequestFinished(false)
return
}
Timber.i(
"At least one permission is missing to use directory %s ",
cacheLocation
)
Settings.cacheLocation = defaultMusicDirectory.path
showWarning(
context, context.getString(R.string.permissions_message_box_title),
context.getString(R.string.permissions_permission_missing), null
)
callback?.onPermissionRequestFinished(false)
}
override fun onPermissionRationaleShouldBeShown(
permissions: List<PermissionRequest>,
token: PermissionToken
) {
showWarning(
context,
context.getString(R.string.permissions_rationale_title),
context.getString(R.string.permissions_rationale_description_failed),
token
)
}
}).withErrorListener { error ->
Timber.e(
"An error has occurred during checking permissions with Dexter: %s",
error.toString()
)
}
.check()
}
private fun showSettingsDialog(ctx: Context) {
val builder = Util.createDialog(
context = ctx,
android.R.drawable.ic_dialog_alert,
ctx.getString(R.string.permissions_permanent_denial_title),
ctx.getString(R.string.permissions_permanent_denial_description)
)
builder.setPositiveButton(ctx.getString(R.string.permissions_open_settings)) {
dialog, _ ->
dialog.cancel()
openSettings(ctx)
}
builder.setNegativeButton(ctx.getString(R.string.common_cancel)) { dialog, _ ->
Settings.cacheLocation = defaultMusicDirectory.path
dialog.cancel()
}
builder.show()
}
private fun openSettings(context: Context) {
val i = Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
i.addCategory(Intent.CATEGORY_DEFAULT)
i.data = Uri.parse("package:" + context.packageName)
context.startActivity(i)
}
private fun showWarning(
context: Context,
title: String,
text: String,
token: PermissionToken?
) {
val builder = Util.createDialog(
context = context,
android.R.drawable.ic_dialog_alert,
title,
text
)
builder.setPositiveButton(context.getString(R.string.common_ok)) { dialog, _ ->
dialog.cancel()
token?.continuePermissionRequest()
}
builder.show()
}
}
}

View File

@ -102,6 +102,23 @@ object Settings {
return if (preloadCount == -1) Int.MAX_VALUE else preloadCount
}
@JvmStatic
var cacheLocation: String
get() {
return preferences.getString(
Constants.PREFERENCES_KEY_CACHE_LOCATION,
FileUtil.defaultMusicDirectory.path
)!!
}
set(location) {
val editor = preferences.edit()
editor.putString(
Constants.PREFERENCES_KEY_CACHE_LOCATION,
location
)
editor.apply()
}
@JvmStatic
val cacheSizeMB: Int
get() {

View File

@ -393,17 +393,30 @@ object Util {
// The AlertDialog requires an Activity context, app context is not enough
// See https://stackoverflow.com/questions/5436822/
fun showDialog(context: Context?, icon: Int, titleId: Int, message: String?) {
AlertDialog.Builder(context)
fun createDialog(
context: Context?,
icon: Int = android.R.drawable.ic_dialog_info,
title: String,
message: String?
): AlertDialog.Builder {
return AlertDialog.Builder(context)
.setIcon(icon)
.setTitle(titleId)
.setTitle(title)
.setMessage(message)
.setPositiveButton(R.string.common_ok) {
dialog: DialogInterface,
_: Int ->
dialog.dismiss()
}
.show()
}
fun showDialog(
context: Context,
icon: Int = android.R.drawable.ic_dialog_info,
titleId: Int,
message: String?
) {
createDialog(context, icon, context.getString(titleId, ""), message).show()
}
@JvmStatic

View File

@ -9,8 +9,8 @@
android:bottomLeftRadius="44dp" />
<padding
android:paddingLeft="22dp"
android:paddingRight="22dp" />
android:paddingStart="22dp"
android:paddingEnd="22dp" />
<solid android:color="@color/selected_color_dark" />

View File

@ -110,8 +110,8 @@
a:layout_width="fill_parent"
a:layout_height="60dip"
a:layout_gravity="bottom|center_horizontal"
a:layout_marginLeft="60dip"
a:layout_marginRight="60dip"
a:layout_marginStart="60dip"
a:layout_marginEnd="60dip"
a:background="@color/translucent"
a:orientation="vertical"/>

View File

@ -15,7 +15,6 @@
a:layout_height="64dp"
a:layout_gravity="center_horizontal|center_vertical"
a:layout_marginStart="6dp"
a:layout_marginLeft="6dp"
a:layout_marginTop="6dp"
a:scaleType="fitCenter"
a:src="@drawable/unknown_album"
@ -28,13 +27,12 @@
a:layout_width="0dp"
a:layout_height="74dp"
a:layout_marginStart="10dp"
a:layout_marginLeft="10dp"
a:drawablePadding="6dip"
a:gravity="center_vertical"
a:minHeight="56dip"
a:orientation="vertical"
a:paddingLeft="3dip"
a:paddingRight="3dip"
a:paddingStart="3dip"
a:paddingEnd="3dip"
a:textAppearance="?android:attr/textAppearanceMedium"
app:layout_constraintEnd_toStartOf="@+id/album_star"
app:layout_constraintLeft_toRightOf="@+id/album_coverart"
@ -65,10 +63,8 @@
a:layout_width="38dp"
a:layout_height="38dp"
a:layout_marginStart="16dp"
a:layout_marginLeft="16dp"
a:layout_marginTop="16dp"
a:layout_marginEnd="20dp"
a:layout_marginRight="20dp"
a:background="@android:color/transparent"
a:gravity="center_horizontal"
a:src="?attr/star_hollow"

View File

@ -9,17 +9,17 @@
a:id="@+id/album_coverart"
a:layout_width="64dp"
a:layout_height="64dp"
a:layout_gravity="left|center_vertical"
a:paddingLeft="3dip" />
a:layout_gravity="start|center_vertical"
a:paddingStart="3dip" />
<LinearLayout
a:orientation="vertical"
a:layout_width="0dip"
a:layout_height="wrap_content"
a:layout_weight="1"
a:layout_gravity="left|center_vertical"
a:paddingLeft="6dip"
a:paddingRight="3dip">
a:layout_gravity="start|center_vertical"
a:paddingStart="6dip"
a:paddingEnd="3dip">
<TextView
a:id="@+id/album_title"
@ -46,6 +46,6 @@
a:background="@android:color/transparent"
a:src="?attr/star_hollow"
a:focusable="false"
a:paddingRight="3dip" />
a:paddingEnd="3dip" />
</LinearLayout>

View File

@ -38,8 +38,8 @@
a:fadingEdge="horizontal"
a:fadingEdgeLength="20dip"
a:minHeight="16sp"
a:paddingLeft="4dip"
a:paddingRight="4dip"
a:paddingStart="4dip"
a:paddingEnd="4dip"
a:paddingTop="4dip"
a:singleLine="true"
a:gravity="center_horizontal"
@ -57,8 +57,8 @@
a:fadingEdgeLength="10dip"
a:minHeight="12sp"
a:paddingBottom="4dip"
a:paddingLeft="4dip"
a:paddingRight="4dip"
a:paddingStart="4dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:gravity="center_horizontal"
a:text="Artist"

View File

@ -40,8 +40,8 @@
a:fadingEdge="horizontal"
a:fadingEdgeLength="20dip"
a:minHeight="16sp"
a:paddingLeft="4dip"
a:paddingRight="4dip"
a:paddingStart="4dip"
a:paddingEnd="4dip"
a:paddingTop="4dip"
a:singleLine="true"
a:gravity="center_horizontal"
@ -58,8 +58,8 @@
a:fadingEdge="horizontal"
a:fadingEdgeLength="10dip"
a:minHeight="12sp"
a:paddingLeft="4dip"
a:paddingRight="4dip"
a:paddingStart="4dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:gravity="center_horizontal"
a:text="Artist"
@ -75,8 +75,8 @@
a:fadingEdgeLength="10dip"
a:minHeight="12sp"
a:paddingBottom="4dip"
a:paddingLeft="4dip"
a:paddingRight="4dip"
a:paddingStart="4dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:gravity="center_horizontal"
a:text="Album"

View File

@ -42,8 +42,8 @@
a:fadingEdge="horizontal"
a:fadingEdgeLength="20dip"
a:minHeight="16sp"
a:paddingLeft="5dip"
a:paddingRight="5dip"
a:paddingStart="5dip"
a:paddingEnd="5dip"
a:singleLine="true"
a:textColor="@color/appwidget_text"
a:textSize="16sp"
@ -61,7 +61,7 @@
a:fadingEdgeLength="10dip"
a:minHeight="12sp"
a:paddingBottom="2dip"
a:paddingLeft="5dip"
a:paddingStart="5dip"
a:singleLine="true"
a:text="Artist"
a:layout_gravity="center_horizontal"

View File

@ -43,8 +43,8 @@
a:fadingEdge="horizontal"
a:fadingEdgeLength="20dip"
a:minHeight="16sp"
a:paddingLeft="5dip"
a:paddingRight="5dip"
a:paddingStart="5dip"
a:paddingEnd="5dip"
a:singleLine="true"
a:textColor="@color/appwidget_text"
a:textSize="16sp"
@ -62,7 +62,7 @@
a:fadingEdgeLength="10dip"
a:minHeight="12sp"
a:paddingBottom="2dip"
a:paddingLeft="5dip"
a:paddingStart="5dip"
a:singleLine="true"
a:text="Artist"
a:layout_gravity="center_horizontal"

View File

@ -16,9 +16,7 @@
a:minWidth="56dip"
a:minHeight="56dip"
a:paddingStart="8dip"
a:paddingLeft="8dip"
a:paddingEnd="8dip"
a:paddingRight="8dip"
a:text="A"
a:textAppearance="?android:attr/textAppearanceLarge"
a:textColor="@color/cyan" />
@ -30,11 +28,8 @@
a:layout_gravity="center_horizontal|center_vertical"
a:layout_marginTop="8dp"
a:layout_marginStart="2dp"
a:layout_marginLeft="2dp"
a:layout_marginEnd="10dp"
a:layout_marginRight="10dp"
a:layout_toEndOf="@+id/row_section"
a:layout_toRightOf="@+id/row_section"
a:scaleType="fitCenter"
a:src="@drawable/ic_contact_picture"
app:shapeAppearanceOverlay="@style/roundedImageView" />
@ -44,13 +39,12 @@
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_toEndOf="@+id/artist_coverart"
a:layout_toRightOf="@+id/artist_coverart"
a:drawablePadding="6dip"
a:gravity="center_vertical"
a:minHeight="56dip"
a:paddingLeft="3dip"
a:paddingRight="3dip"
a:layout_marginRight="12dp"
a:paddingStart="3dip"
a:paddingEnd="3dip"
a:layout_marginEnd="12dp"
a:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>

View File

@ -20,8 +20,8 @@
a:id="@+id/chat_username"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginLeft="6dip"
a:layout_marginRight="6dip"
a:layout_marginStart="6dip"
a:layout_marginEnd="6dip"
a:ellipsize="marquee"
a:singleLine="true"
a:textIsSelectable="true"
@ -43,7 +43,7 @@
a:id="@+id/chat_time"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginLeft="6dip"
a:layout_marginStart="6dip"
a:singleLine="true"
a:textIsSelectable="true"
a:textAppearance="?android:attr/textAppearanceMedium"
@ -53,8 +53,8 @@
a:id="@+id/chat_message"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginLeft="6dip"
a:layout_marginRight="6dip"
a:layout_marginStart="6dip"
a:layout_marginEnd="6dip"
a:textIsSelectable="true"
a:linksClickable="true"
a:singleLine="false"

View File

@ -17,7 +17,7 @@
a:id="@+id/chat_username"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginRight="6dip"
a:layout_marginEnd="6dip"
a:gravity="center_vertical|right"
a:layout_gravity="right"
a:ellipsize="marquee"
@ -38,7 +38,7 @@
a:id="@+id/chat_time"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginLeft="6dip"
a:layout_marginStart="6dip"
a:singleLine="true"
a:gravity="center_vertical|right"
a:textIsSelectable="true"
@ -49,8 +49,8 @@
a:id="@+id/chat_message"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginLeft="6dip"
a:layout_marginRight="6dip"
a:layout_marginStart="6dip"
a:layout_marginEnd="6dip"
a:linksClickable="true"
a:singleLine="false"
a:autoLink="all"

View File

@ -110,8 +110,8 @@
a:layout_height="60dip"
a:layout_gravity="center"
a:background="@color/translucent"
a:layout_marginLeft="80dip"
a:layout_marginRight="80dip"
a:layout_marginStart="80dip"
a:layout_marginEnd="80dip"
a:orientation="vertical"
/>

View File

@ -36,8 +36,8 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dip"
android:paddingLeft="40dip"
android:paddingRight="40dip"/>
android:paddingStart="40dip"
android:paddingEnd="40dip"/>
</LinearLayout>
</ScrollView>

View File

@ -24,7 +24,7 @@
a:layout_height="wrap_content"
a:layout_marginTop="8dp"
a:layout_alignParentRight="true"
a:layout_toRightOf="@+id/equalizer.frequency"
a:layout_toEndOf="@+id/equalizer.frequency"
/>
<SeekBar

View File

@ -29,10 +29,8 @@
a:layout_height="wrap_content"
a:layout_alignParentBottom="true"
a:layout_marginStart="10dp"
a:layout_marginLeft="10dp"
a:layout_marginTop="10dp"
a:layout_marginEnd="10dp"
a:layout_marginRight="10dp"
a:layout_marginBottom="10dp"
a:drawableStart="?attr/filepicker_create_new_folder"
a:drawableLeft="?attr/filepicker_create_new_folder"

View File

@ -19,7 +19,6 @@
a:layout_height="wrap_content"
a:layout_gravity="center_vertical"
a:layout_marginStart="20dp"
a:layout_marginLeft="20dp"
a:gravity="center_vertical"
a:text=""
a:textSize="18sp" />

View File

@ -6,6 +6,6 @@
a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium"
a:gravity="center_vertical"
a:paddingLeft="3dip"
a:paddingRight="3dip"
a:paddingStart="3dip"
a:paddingEnd="3dip"
a:minHeight="50dip"/>

View File

@ -14,8 +14,8 @@
a:textColor="#ffffffff"
a:shadowColor="#bb000000"
a:shadowRadius="2.75"
a:paddingLeft="32dp"
a:paddingRight="32dp"
a:paddingStart="32dp"
a:paddingEnd="32dp"
a:paddingBottom="12dp"
/>

View File

@ -28,8 +28,8 @@
a:gravity="center_horizontal"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:paddingLeft="10dip"
a:paddingRight="10dip"
a:paddingStart="10dip"
a:paddingEnd="10dip"
a:paddingTop="10dip"
a:paddingBottom="4dip"
/>
@ -40,8 +40,8 @@
a:gravity="center_horizontal"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:paddingLeft="10dip"
a:paddingRight="10dip"
a:paddingStart="10dip"
a:paddingEnd="10dip"
/>
<TextView
@ -51,8 +51,8 @@
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:paddingTop="32dip"
a:paddingLeft="10dip"
a:paddingRight="10dip"
a:paddingStart="10dip"
a:paddingEnd="10dip"
/>
</LinearLayout>

View File

@ -4,7 +4,7 @@
<LinearLayout a:id="@+id/main_select_server"
a:orientation="horizontal" a:paddingTop="2dip" a:paddingBottom="2dip"
a:paddingLeft="10dp" a:layout_width="fill_parent" a:layout_height="wrap_content"
a:paddingStart="10dp" a:layout_width="fill_parent" a:layout_height="wrap_content"
a:minHeight="?android:attr/listPreferredItemHeight">
<ImageView a:layout_width="wrap_content" a:layout_height="wrap_content"
@ -19,7 +19,7 @@
a:id="@+id/main.select_server_1"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_marginLeft="10dip"
a:layout_marginStart="10dip"
a:layout_marginTop="6dip"
a:text="@string/main.select_server"
a:textAppearance="?android:attr/textAppearanceLarge" />
@ -28,7 +28,7 @@
a:id="@+id/main.select_server_2"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_marginLeft="10dip"
a:layout_marginStart="10dip"
a:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
@ -37,95 +37,95 @@
<TextView a:id="@+id/main_music" a:text="@string/main.music"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceSmall" a:textColor="@color/cyan"
a:gravity="center_vertical" a:paddingLeft="6dp" a:textAllCaps="true"
a:gravity="center_vertical" a:paddingStart="6dp" a:textAllCaps="true"
a:textStyle="bold" />
<TextView a:id="@+id/main_artists_button" a:text="@string/main.artists_title"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_albums_button" a:text="@string/main.albums_title"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_genres_button" a:text="@string/main.genres_title"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_songs" a:text="@string/main.songs_title"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceSmall" a:textColor="@color/cyan"
a:gravity="center_vertical" a:paddingLeft="6dp" a:textAllCaps="true"
a:gravity="center_vertical" a:paddingStart="6dp" a:textAllCaps="true"
a:textStyle="bold" />
<TextView a:id="@+id/main_songs_button" a:text="@string/main.songs_random"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_songs_starred" a:text="@string/main.songs_starred"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_albums" a:text="@string/main.albums_title"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceSmall" a:textColor="@color/cyan"
a:gravity="center_vertical" a:paddingLeft="6dp" a:textAllCaps="true"
a:gravity="center_vertical" a:paddingStart="6dp" a:textAllCaps="true"
a:textStyle="bold" />
<TextView a:id="@+id/main_albums_newest" a:text="@string/main.albums_newest"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_albums_recent" a:text="@string/main.albums_recent"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_albums_frequent" a:text="@string/main.albums_frequent"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_albums_highest" a:text="@string/main.albums_highest"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_albums_random" a:text="@string/main.albums_random"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceMedium" a:gravity="center_vertical"
a:paddingLeft="6dip" a:paddingRight="6dip" a:minHeight="40dip" />
a:paddingStart="6dip" a:paddingEnd="6dip" a:minHeight="40dip" />
<TextView a:id="@+id/main_albums_starred" a:layout_width="fill_parent"
a:layout_height="wrap_content" a:gravity="center_vertical"
a:minHeight="40dip" a:paddingLeft="6dip" a:paddingRight="6dip"
a:minHeight="40dip" a:paddingStart="6dip" a:paddingEnd="6dip"
a:text="@string/main.albums_starred" a:textAppearance="?android:attr/textAppearanceMedium" />
<TextView a:id="@+id/main_albums_alphaByName" a:layout_width="fill_parent"
a:layout_height="wrap_content" a:gravity="center_vertical"
a:minHeight="40dip" a:paddingLeft="6dip" a:paddingRight="6dip"
a:minHeight="40dip" a:paddingStart="6dip" a:paddingEnd="6dip"
a:text="@string/main.albums_alphaByName" a:textAppearance="?android:attr/textAppearanceMedium" />
<TextView a:id="@+id/main_albums_alphaByArtist" a:layout_width="fill_parent"
a:layout_height="wrap_content" a:gravity="center_vertical"
a:minHeight="40dip" a:paddingLeft="6dip" a:paddingRight="6dip"
a:minHeight="40dip" a:paddingStart="6dip" a:paddingEnd="6dip"
a:text="@string/main.albums_alphaByArtist" a:textAppearance="?android:attr/textAppearanceMedium" />
<TextView a:id="@+id/main_videos_title" a:text="@string/main.videos"
a:layout_width="fill_parent" a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceSmall" a:textColor="@color/cyan"
a:gravity="center_vertical" a:paddingLeft="6dp" a:textAllCaps="true"
a:gravity="center_vertical" a:paddingStart="6dp" a:textAllCaps="true"
a:textStyle="bold" />
<TextView a:id="@+id/main_videos" a:layout_width="fill_parent"
a:layout_height="wrap_content" a:gravity="center_vertical"
a:minHeight="40dip" a:paddingLeft="6dip" a:paddingRight="6dip"
a:minHeight="40dip" a:paddingStart="6dip" a:paddingEnd="6dip"
a:text="@string/main.videos" a:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

View File

@ -4,8 +4,8 @@
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:orientation="horizontal"
a:layout_marginLeft="12dp"
a:layout_marginRight="12dp" >
a:layout_marginStart="12dp"
a:layout_marginEnd="12dp" >
<ImageView
a:id="@+id/button_shuffle"

View File

@ -33,7 +33,6 @@
a:layout_height="match_parent"
a:gravity="center_vertical"
a:paddingStart="16dp"
a:paddingLeft="16dp"
a:text="@string/common.appname"
a:textAppearance="@style/TextAppearance.AppCompat.Title" />

View File

@ -19,7 +19,6 @@
android:id="@+id/now_playing_image"
android:layout_width="64.0dip"
android:layout_height="64.0dip"
android:layout_marginLeft="6dp"
android:focusable="true"
android:gravity="center"
android:layout_marginStart="6dp" />
@ -30,14 +29,13 @@
android:layout_gravity="center_vertical"
android:layout_weight="1.0"
android:orientation="vertical"
android:paddingLeft="11.0dip"
android:paddingStart="11.0dip">
<TextView
android:id="@+id/now_playing_trackname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_gravity="start"
android:ellipsize="marquee"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
@ -47,7 +45,7 @@
android:id="@+id/now_playing_artist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_gravity="start"
android:ellipsize="end"
android:scrollHorizontally="true"
android:singleLine="true"
@ -58,9 +56,9 @@
android:id="@+id/now_playing_control_play"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center|right"
android:layout_gravity="center|end"
android:layout_marginTop="2dip"
android:layout_marginRight="16dip"
android:layout_marginEnd="16dip"
android:layout_weight="0.0"
android:focusable="false"
android:scaleType="fitCenter"

View File

@ -5,8 +5,8 @@
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_marginTop="10dp"
a:layout_marginLeft="12dp"
a:layout_marginRight="12dp" >
a:layout_marginStart="12dp"
a:layout_marginEnd="12dp" >
<LinearLayout
a:layout_width="wrap_content"

View File

@ -4,8 +4,8 @@
a:layout_height="wrap_content"
a:orientation="vertical"
a:layout_marginTop="10dp"
a:layout_marginLeft="12dp"
a:layout_marginRight="12dp" >
a:layout_marginStart="12dp"
a:layout_marginEnd="12dp" >
<SeekBar
a:id="@+id/current_playing_progress_bar"
@ -22,7 +22,7 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_alignParentLeft="true"
a:layout_marginLeft="12dip"
a:layout_marginStart="12dip"
a:text="@string/util.no_time"
a:textAppearance="?android:attr/textAppearanceSmall" />
@ -31,7 +31,7 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_alignParentRight="true"
a:layout_marginRight="12dip"
a:layout_marginEnd="12dip"
a:text="@string/util.no_time"
a:textAppearance="?android:attr/textAppearanceSmall" />

View File

@ -11,8 +11,8 @@
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="left|center_vertical"
android:paddingLeft="6dip"
android:paddingRight="6dip"
android:paddingStart="6dip"
android:paddingEnd="6dip"
android:minHeight="50dip"/>
</LinearLayout>

View File

@ -24,7 +24,7 @@
a:textStyle="bold"
a:background="#ff555555"
a:gravity="center_vertical"
a:paddingLeft="4dp"/>
a:paddingStart="4dp"/>
<TextView
a:id="@+id/search_albums"
@ -36,7 +36,7 @@
a:textStyle="bold"
a:background="#ff555555"
a:gravity="center_vertical"
a:paddingLeft="4dp"/>
a:paddingStart="4dp"/>
<TextView
a:id="@+id/search_songs"
@ -48,7 +48,7 @@
a:textStyle="bold"
a:background="#ff555555"
a:gravity="center_vertical"
a:paddingLeft="4dp"/>
a:paddingStart="4dp"/>
<TextView
a:id="@+id/search_more_artists"

View File

@ -9,7 +9,7 @@
a:layout_height="160dip"
a:layout_alignParentLeft="true"
a:layout_alignParentTop="true"
a:layout_marginRight="10dip"
a:layout_marginEnd="10dip"
a:contentDescription="@null"
a:scaleType="fitCenter"
a:src="@drawable/unknown_album"/>
@ -18,9 +18,9 @@
a:id="@+id/select_album_title"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_toRightOf="@+id/select_album_art"
a:layout_toEndOf="@+id/select_album_art"
a:ellipsize="end"
a:paddingRight="4dip"
a:paddingEnd="4dip"
a:paddingTop="10dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceMedium"/>
@ -30,9 +30,9 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_below="@+id/select_album_title"
a:layout_toRightOf="@+id/select_album_art"
a:layout_toEndOf="@+id/select_album_art"
a:ellipsize="end"
a:paddingRight="4dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>
@ -41,9 +41,9 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_below="@+id/select_album_artist"
a:layout_toRightOf="@+id/select_album_art"
a:layout_toEndOf="@+id/select_album_art"
a:ellipsize="end"
a:paddingRight="4dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>
@ -52,9 +52,9 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_below="@+id/select_album_genre"
a:layout_toRightOf="@+id/select_album_art"
a:layout_toEndOf="@+id/select_album_art"
a:ellipsize="end"
a:paddingRight="4dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>
@ -63,9 +63,9 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_below="@+id/select_album_year"
a:layout_toRightOf="@+id/select_album_art"
a:layout_toEndOf="@+id/select_album_art"
a:ellipsize="none"
a:paddingRight="4dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>
@ -74,9 +74,9 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_below="@+id/select_album_song_count"
a:layout_toRightOf="@+id/select_album_art"
a:layout_toEndOf="@+id/select_album_art"
a:ellipsize="none"
a:paddingRight="4dip"
a:paddingEnd="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>

View File

@ -6,7 +6,7 @@
a:minHeight="?android:attr/listPreferredItemHeight"
a:orientation="horizontal"
a:paddingBottom="2dip"
a:paddingLeft="6dp"
a:paddingStart="6dp"
a:paddingTop="2dip"
a:background="?android:attr/selectableItemBackground"
a:clickable="true"
@ -27,7 +27,7 @@
a:id="@+id/select_folder_title"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_marginLeft="10dip"
a:layout_marginStart="10dip"
a:layout_marginTop="6dip"
a:text="@string/select_artist.folder"
a:textAppearance="?android:attr/textAppearanceLarge" />
@ -36,7 +36,7 @@
a:id="@+id/select_folder_name"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_marginLeft="10dip"
a:layout_marginStart="10dip"
a:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>

View File

@ -110,7 +110,6 @@
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_marginStart="5dp"
a:layout_marginLeft="5dp"
a:text="@string/settings.title.allow_self_signed_certificate"
app:layout_constraintBottom_toTopOf="@id/edit_ldap_title"
app:layout_constraintStart_toStartOf="parent"
@ -121,9 +120,7 @@
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_marginStart="8dp"
a:layout_marginLeft="8dp"
a:layout_marginEnd="5dp"
a:layout_marginRight="5dp"
a:layout_marginBottom="8dp"
a:checked="false"
app:layout_constraintBottom_toTopOf="@id/edit_ldap_title"
@ -137,7 +134,6 @@
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_marginStart="5dp"
a:layout_marginLeft="5dp"
a:text="@string/settings.title.enable_ldap_users_support"
app:layout_constraintBottom_toTopOf="@id/edit_ldap_description"
app:layout_constraintStart_toStartOf="parent"
@ -149,7 +145,6 @@
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_marginStart="5dp"
a:layout_marginLeft="5dp"
a:text="@string/settings.summary.enable_ldap_users_support"
app:layout_constraintBottom_toTopOf="@id/edit_jukebox"
app:layout_constraintEnd_toStartOf="@id/edit_ldap"
@ -161,8 +156,6 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginEnd="5dp"
a:layout_marginRight="5dp"
a:layout_marginLeft="8dp"
a:layout_marginStart="8dp"
a:checked="false"
app:layout_constraintBottom_toBottomOf="@id/edit_ldap_description"
@ -176,7 +169,6 @@
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_marginStart="5dp"
a:layout_marginLeft="5dp"
a:layout_marginTop="8dp"
a:text="@string/jukebox.is_default"
app:layout_constraintStart_toStartOf="parent"
@ -187,10 +179,8 @@
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_marginStart="8dp"
a:layout_marginLeft="8dp"
a:layout_marginTop="8dp"
a:layout_marginEnd="5dp"
a:layout_marginRight="5dp"
a:checked="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/edit_jukebox_title"

View File

@ -21,7 +21,6 @@
a:layout_height="wrap_content"
a:textAppearance="?android:attr/textAppearanceListItem"
a:paddingTop="10dp"
a:layout_toRightOf="@id/server_image"
a:layout_toEndOf="@id/server_image" />
<TextView
@ -31,7 +30,6 @@
a:textAppearance="?android:attr/textAppearanceSmall"
a:layout_below="@id/server_name"
a:paddingBottom="10dp"
a:layout_toRightOf="@id/server_image"
a:layout_toEndOf="@id/server_image" />
<ImageButton
@ -43,7 +41,7 @@
a:layout_centerVertical="true"
a:layout_gravity="end"
a:layout_marginEnd="15dp"
a:layout_marginRight="15dp"
a:focusable="false"
a:src="?attr/more_vert"
a:padding="5dp" />

View File

@ -4,8 +4,8 @@
a:layout_height="wrap_content"
a:layout_gravity="center_vertical"
a:layout_weight="1"
a:paddingLeft="6dip"
a:paddingRight="6dip"
a:paddingStart="6dip"
a:paddingEnd="6dip"
a:minHeight="44dip"
a:orientation="vertical">
@ -38,7 +38,7 @@
a:layout_gravity="left|center_vertical"
a:layout_weight="1"
a:ellipsize="middle"
a:paddingLeft="4dip"
a:paddingStart="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>

View File

@ -4,7 +4,7 @@
a:layout_height="wrap_content"
a:layout_gravity="center_vertical"
a:layout_weight="1"
a:layout_marginLeft="4dp"
a:layout_marginStart="4dp"
a:orientation="vertical">
<LinearLayout
@ -28,8 +28,8 @@
a:layout_weight="1"
a:drawablePadding="6dip"
a:ellipsize="end"
a:paddingLeft="4dip"
a:paddingRight="2dip"
a:paddingStart="4dip"
a:paddingEnd="2dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceMedium"/>
@ -39,7 +39,7 @@
a:layout_height="wrap_content"
a:layout_gravity="right|center_vertical"
a:drawablePadding="6dip"
a:paddingRight="6dip"/>
a:paddingEnd="6dip"/>
</LinearLayout>
<LinearLayout
@ -55,7 +55,7 @@
a:layout_gravity="left|center_vertical"
a:layout_weight="1"
a:ellipsize="middle"
a:paddingLeft="4dip"
a:paddingStart="4dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>
@ -64,8 +64,8 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_gravity="right|center_vertical"
a:paddingLeft="3dip"
a:paddingRight="9dip"
a:paddingStart="3dip"
a:paddingEnd="9dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>
</LinearLayout>

View File

@ -11,9 +11,7 @@
a:id="@+id/song_drag"
a:layout_width="wrap_content"
a:layout_height="fill_parent"
a:paddingLeft="5dip"
a:paddingStart="5dip"
a:paddingRight="0dip"
a:paddingEnd="0dip"
a:background="@android:color/transparent"
a:focusable="false"
@ -26,7 +24,7 @@
a:layout_height="fill_parent"
a:checkMark="?attr/button_check_custom"
a:gravity="center_vertical"
a:paddingRight="4dip"/>
a:paddingEnd="4dip"/>
<include layout="@layout/song_details" />
@ -82,7 +80,7 @@
a:id="@+id/song_five_star_5"
a:layout_width="10dip"
a:layout_height="fill_parent"
a:layout_marginRight="8dip"
a:layout_marginEnd="8dip"
a:background="@android:color/transparent"
a:focusable="false"
a:gravity="center_vertical"
@ -98,7 +96,7 @@
a:background="@android:color/transparent"
a:focusable="false"
a:gravity="center_vertical"
a:paddingRight="8dip"
a:paddingEnd="8dip"
a:src="?attr/star_hollow" />
</LinearLayout>

View File

@ -44,7 +44,7 @@
android:layout_height="wrap_content"
android:id="@+id/timeSpanSpinner"
android:layout_alignBottom="@+id/timeSpanEditText"
android:layout_toRightOf="@+id/timeSpanEditText"/>
android:layout_toEndOf="@+id/timeSpanEditText"/>
</RelativeLayout>
</LinearLayout>

View File

@ -12,7 +12,7 @@
android:id="@+id/get_playlist_name_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textSize="20sp"
android:text="@string/common.name" />
<EditText
@ -21,7 +21,7 @@
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:hint="@string/common.name" />
</LinearLayout>
@ -34,7 +34,7 @@
android:id="@+id/get_playlist_comment_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textSize="20sp"
android:text="@string/common.comment" />
<EditText
@ -43,7 +43,7 @@
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:hint="@string/common.comment" />
</LinearLayout>
@ -56,7 +56,7 @@
android:id="@+id/get_playlist_public_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:textSize="20sp"
android:text="@string/common.public" />
<CheckBox
@ -64,7 +64,7 @@
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:checked="false"/>
</LinearLayout>
</LinearLayout>

View File

@ -19,8 +19,8 @@
a:layout_gravity="left|center_vertical"
a:layout_weight="1"
a:ellipsize="end"
a:paddingLeft="4dip"
a:paddingRight="2dip"
a:paddingStart="4dip"
a:paddingEnd="2dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceMedium"/>
@ -29,8 +29,8 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_gravity="right|center_vertical"
a:paddingLeft="2dip"
a:paddingRight="6dip"
a:paddingStart="2dip"
a:paddingEnd="6dip"
a:singleLine="true"
a:textAppearance="?android:attr/textAppearanceSmall"/>
</LinearLayout>

View File

@ -10,7 +10,7 @@
a:layout_width="wrap_content"
a:layout_height="fill_parent"
a:gravity="center_vertical"
a:paddingLeft="1dip"
a:paddingStart="1dip"
a:visibility="gone" />
<include layout="@layout/video_details"
@ -23,7 +23,7 @@
a:background="@android:color/transparent"
a:focusable="false"
a:gravity="center_vertical"
a:paddingRight="8dip"
a:paddingEnd="8dip"
a:src="?attr/star_hollow" />
</LinearLayout>

View File

@ -420,43 +420,36 @@
<plurals name="select_album_n_songs">
<item quantity="one">%d skladba</item>
<item quantity="few">%d skladby</item>
<item quantity="many">%d skladeb</item>
<item quantity="other">%d skladeb</item>
</plurals>
<plurals name="select_album_n_songs_pinned">
<item quantity="one">%d skladba vybrána pro připnutí.</item>
<item quantity="few">%d skladby vybrány pro připnutí.</item>
<item quantity="many">%d skladeb vybráno pro připnutí.</item>
<item quantity="other">%d skladeb vybráno pro připnutí.</item>
</plurals>
<plurals name="select_album_n_songs_downloaded">
<item quantity="one">%d skladba vybrána pro stažení.</item>
<item quantity="few">%d skladby vybrány pro stažení.</item>
<item quantity="many">%d skladeb vybráno pro stažení.</item>
<item quantity="other">%d skladeb vybráno pro stažení.</item>
</plurals>
<plurals name="select_album_n_songs_unpinned">
<item quantity="one">%d skladba vybrána pro odepnutí.</item>
<item quantity="few">%d skladby vybrány pro odepnutí.</item>
<item quantity="many">%d skladeb vybráno pro odepnutí.</item>
<item quantity="other">%d skladeb vybráno pro odepnutí.</item>
</plurals>
<plurals name="select_album_n_songs_added">
<item quantity="one">%d skladba přidána na konec fronty přehrávání.</item>
<item quantity="few">%d skladyb přidány na konec fronty přehrávání.</item>
<item quantity="many">%d skladeb přidáno na konec fronty přehrávání.</item>
<item quantity="other">%d skladeb přidáno na konec fronty přehrávání.</item>
</plurals>
<plurals name="select_album_n_songs_play_next">
<item quantity="one">%d skladba přidána za aktuální skladbu.</item>
<item quantity="few">%d skladby přidány za aktuální skladbu.</item>
<item quantity="many">%d skladeb přidáno za aktuální skladbu.</item>
<item quantity="other">%d skladeb přidáno za aktuální skladbu.</item>
</plurals>
<plurals name="select_album_donate_dialog_n_trial_days_left">
<item quantity="one">Zbývá %d den zkušební doby</item>
<item quantity="few">Zbývají %d dny zkušební doby</item>
<item quantity="many">Zbývá %d dní zkušební doby</item>
<item quantity="other">Zbývá %d dní zkušební doby</item>
</plurals>

View File

@ -15,7 +15,7 @@
<item name="android:textSize">14sp</item>
<item name="android:textAllCaps">true</item>
<item name="android:gravity">center_vertical</item>
<item name="android:paddingLeft">16dp</item>
<item name="android:paddingStart">16dp</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
</style>

View File

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:a="http://schemas.android.com/apk/res/android"
a:minWidth="250dp"
a:minHeight="40dp"
a:updatePeriodMillis="0"
a:resizeMode="none"
a:previewImage="@drawable/preview4x1"
a:widgetCategory="home_screen|keyguard"
a:initialLayout="@layout/appwidget4x1"/>
xmlns:tools="http://schemas.android.com/tools"
a:minWidth="250dp"
a:minHeight="40dp"
a:updatePeriodMillis="0"
a:resizeMode="none"
a:previewImage="@drawable/preview4x1"
a:widgetCategory="home_screen|keyguard"
a:initialLayout="@layout/appwidget4x1"
tools:ignore="UnusedAttribute" />

View File

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:a="http://schemas.android.com/apk/res/android"
a:minWidth="250dp"
a:minHeight="110dp"
a:updatePeriodMillis="0"
a:resizeMode="none"
a:previewImage="@drawable/preview4x2"
a:widgetCategory="home_screen|keyguard"
a:initialLayout="@layout/appwidget4x2"/>
xmlns:tools="http://schemas.android.com/tools"
a:minWidth="250dp"
a:minHeight="110dp"
a:updatePeriodMillis="0"
a:resizeMode="none"
a:previewImage="@drawable/preview4x2"
a:widgetCategory="home_screen|keyguard"
a:initialLayout="@layout/appwidget4x2"
tools:ignore="UnusedAttribute" />