Merge pull request #500 from tzugen/detekt-3
Fix a lot of warnings, update baseline files, improve CI run times
This commit is contained in:
commit
6943dc5895
|
@ -2,23 +2,28 @@ version: 3
|
|||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/android:api-28
|
||||
- image: circleci/android:api-29
|
||||
working_directory: ~/ultrasonic
|
||||
environment:
|
||||
JVM_OPTS: -Xmx3200m
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: gradle-cache-{{ checksum "dependencies.gradle" }}
|
||||
keys:
|
||||
- v1-ultrasonic-{{ .Branch }}-{{ checksum "dependencies.gradle" }}
|
||||
- v1-ultrasonic-{{ .Branch }}
|
||||
- v1-ultrasonic
|
||||
- run:
|
||||
name: clean gradle.properties
|
||||
command: echo -e "android.useAndroidX=true\nandroid.enableJetifier=true\n" > gradle.properties
|
||||
name: configure gradle.properties for CI building
|
||||
command: |
|
||||
sed -i '/^org.gradle.jvmargs/d' gradle.properties
|
||||
sed -i 's/^org.gradle.daemon=true/org.gradle.daemon=false/g' gradle.properties
|
||||
- run:
|
||||
name: checkstyle
|
||||
command: ./gradlew -Pqc ktlintCheck
|
||||
- run:
|
||||
name: static analysis
|
||||
command: ./gradlew -Pqc detektMain
|
||||
command: ./gradlew -Pqc detekt
|
||||
- run:
|
||||
name: build
|
||||
command: ./gradlew assembleDebug
|
||||
|
@ -36,7 +41,7 @@ jobs:
|
|||
- save_cache:
|
||||
paths:
|
||||
- ~/.gradle
|
||||
key: gradle-cache-{{ checksum "dependencies.gradle" }}
|
||||
key: v1-ultrasonic-{{ .Branch }}-{{ checksum "dependencies.gradle" }}
|
||||
- store_artifacts:
|
||||
path: ultrasonic/build/reports
|
||||
destination: reports
|
||||
|
@ -72,7 +77,10 @@ jobs:
|
|||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: gradle-cache-{{ checksum "dependencies.gradle" }}
|
||||
keys:
|
||||
- v1-ultrasonic-{{ .Branch }}-{{ checksum "dependencies.gradle" }}
|
||||
- v1-ultrasonic-{{ .Branch }}
|
||||
- v1-ultrasonic
|
||||
- run:
|
||||
name: decrypt ultrasonic-keystore
|
||||
command: openssl aes-256-cbc -K ${ULTRASONIC_KEYSTORE_KEY} -iv ${ULTRASONIC_KEYSTORE_IV} -in ultrasonic-keystore.enc -out ultrasonic-keystore -d
|
||||
|
|
|
@ -33,6 +33,7 @@ allprojects {
|
|||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
apply from: bootstrap.androidModule
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
lintOptions {
|
||||
baselineFile file("lint-baseline.xml")
|
||||
abortOnError true
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api androidSupport.support
|
||||
implementation other.timber
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issues format="4" by="lint 2.3.3">
|
||||
|
||||
<issue
|
||||
id="NewApi"
|
||||
message="Call requires API level 21 (current min is 14): android.widget.AbsListView#setSelectionFromTop"
|
||||
errorLine1=" setSelectionFromTop(movePos, top - padTop);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/mobeta/android/dslv/DragSortListView.java"
|
||||
line="2936"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="OldTargetApi"
|
||||
message="Not targeting the latest versions of Android; compatibility modes apply. Consider testing and updating this version. Consult the `android.os.Build.VERSION_CODES` javadoc for details."
|
||||
errorLine1=" <uses-sdk android:targetSdkVersion="7""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/AndroidManifest.xml"
|
||||
line="6"
|
||||
column="15"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleOverrides"
|
||||
message="This `targetSdkVersion` value (`7`) is not used; it is always overridden by the value specified in the Gradle build script (`22`)"
|
||||
errorLine1=" <uses-sdk android:targetSdkVersion="7""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/AndroidManifest.xml"
|
||||
line="6"
|
||||
column="15"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="GradleOverrides"
|
||||
message="This `minSdkVersion` value (`7`) is not used; it is always overridden by the value specified in the Gradle build script (`14`)"
|
||||
errorLine1=" android:minSdkVersion="7" />"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/AndroidManifest.xml"
|
||||
line="7"
|
||||
column="7"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="ClickableViewAccessibility"
|
||||
message="`com/mobeta/android/dslv/DragSortController#onTouch` should call `View#performClick` when a click is detected"
|
||||
errorLine1=" public boolean onTouch(View v, MotionEvent ev) {"
|
||||
errorLine2=" ~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/mobeta/android/dslv/DragSortController.java"
|
||||
line="238"
|
||||
column="20"/>
|
||||
</issue>
|
||||
|
||||
</issues>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mobeta.android.dslv"
|
||||
android:versionCode="4"
|
||||
android:versionName="0.6.1">
|
||||
</manifest>
|
|
@ -1,465 +0,0 @@
|
|||
package com.mobeta.android.dslv;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
/**
|
||||
* Class that starts and stops item drags on a {@link DragSortListView}
|
||||
* based on touch gestures. This class also inherits from
|
||||
* {@link SimpleFloatViewManager}, which provides basic float View
|
||||
* creation.
|
||||
*
|
||||
* An instance of this class is meant to be passed to the methods
|
||||
* {@link DragSortListView#setTouchListener()} and
|
||||
* {@link DragSortListView#setFloatViewManager()} of your
|
||||
* {@link DragSortListView} instance.
|
||||
*/
|
||||
public class DragSortController extends SimpleFloatViewManager implements View.OnTouchListener, GestureDetector.OnGestureListener {
|
||||
|
||||
/**
|
||||
* Drag init mode enum.
|
||||
*/
|
||||
public static final int ON_DOWN = 0;
|
||||
public static final int ON_DRAG = 1;
|
||||
public static final int ON_LONG_PRESS = 2;
|
||||
|
||||
private int mDragInitMode = ON_DOWN;
|
||||
|
||||
private boolean mSortEnabled = true;
|
||||
|
||||
/**
|
||||
* Remove mode enum.
|
||||
*/
|
||||
public static final int CLICK_REMOVE = 0;
|
||||
public static final int FLING_REMOVE = 1;
|
||||
|
||||
/**
|
||||
* The current remove mode.
|
||||
*/
|
||||
private int mRemoveMode;
|
||||
|
||||
private boolean mRemoveEnabled = false;
|
||||
private boolean mIsRemoving = false;
|
||||
|
||||
private GestureDetector mDetector;
|
||||
|
||||
private GestureDetector mFlingRemoveDetector;
|
||||
|
||||
private int mTouchSlop;
|
||||
|
||||
public static final int MISS = -1;
|
||||
|
||||
private int mHitPos = MISS;
|
||||
private int mFlingHitPos = MISS;
|
||||
|
||||
private int mClickRemoveHitPos = MISS;
|
||||
|
||||
private int[] mTempLoc = new int[2];
|
||||
|
||||
private int mItemX;
|
||||
private int mItemY;
|
||||
|
||||
private int mCurrX;
|
||||
private int mCurrY;
|
||||
|
||||
private boolean mDragging = false;
|
||||
|
||||
private float mFlingSpeed = 500f;
|
||||
|
||||
private int mDragHandleId;
|
||||
|
||||
private int mClickRemoveId;
|
||||
|
||||
private int mFlingHandleId;
|
||||
private boolean mCanDrag;
|
||||
|
||||
private DragSortListView mDslv;
|
||||
private int mPositionX;
|
||||
|
||||
/**
|
||||
* Calls {@link #DragSortController(DragSortListView, int)} with a
|
||||
* 0 drag handle id, FLING_RIGHT_REMOVE remove mode,
|
||||
* and ON_DOWN drag init. By default, sorting is enabled, and
|
||||
* removal is disabled.
|
||||
*
|
||||
* @param dslv The DSLV instance
|
||||
*/
|
||||
public DragSortController(DragSortListView dslv) {
|
||||
this(dslv, 0, ON_DOWN, FLING_REMOVE);
|
||||
}
|
||||
|
||||
public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, int removeMode) {
|
||||
this(dslv, dragHandleId, dragInitMode, removeMode, 0);
|
||||
}
|
||||
|
||||
public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode, int removeMode, int clickRemoveId) {
|
||||
this(dslv, dragHandleId, dragInitMode, removeMode, clickRemoveId, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, sorting is enabled, and removal is disabled.
|
||||
*
|
||||
* @param dslv The DSLV instance
|
||||
* @param dragHandleId The resource id of the View that represents
|
||||
* the drag handle in a list item.
|
||||
*/
|
||||
public DragSortController(DragSortListView dslv, int dragHandleId, int dragInitMode,
|
||||
int removeMode, int clickRemoveId, int flingHandleId) {
|
||||
super(dslv);
|
||||
mDslv = dslv;
|
||||
mDetector = new GestureDetector(dslv.getContext(), this);
|
||||
mFlingRemoveDetector = new GestureDetector(dslv.getContext(), mFlingRemoveListener);
|
||||
mFlingRemoveDetector.setIsLongpressEnabled(false);
|
||||
mTouchSlop = ViewConfiguration.get(dslv.getContext()).getScaledTouchSlop();
|
||||
mDragHandleId = dragHandleId;
|
||||
mClickRemoveId = clickRemoveId;
|
||||
mFlingHandleId = flingHandleId;
|
||||
setRemoveMode(removeMode);
|
||||
setDragInitMode(dragInitMode);
|
||||
}
|
||||
|
||||
|
||||
public int getDragInitMode() {
|
||||
return mDragInitMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set how a drag is initiated. Needs to be one of
|
||||
* {@link ON_DOWN}, {@link ON_DRAG}, or {@link ON_LONG_PRESS}.
|
||||
*
|
||||
* @param mode The drag init mode.
|
||||
*/
|
||||
public void setDragInitMode(int mode) {
|
||||
mDragInitMode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable list item sorting. Disabling is useful if only item
|
||||
* removal is desired. Prevents drags in the vertical direction.
|
||||
*
|
||||
* @param enabled Set <code>true</code> to enable list
|
||||
* item sorting.
|
||||
*/
|
||||
public void setSortEnabled(boolean enabled) {
|
||||
mSortEnabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isSortEnabled() {
|
||||
return mSortEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* One of {@link CLICK_REMOVE}, {@link FLING_RIGHT_REMOVE},
|
||||
* {@link FLING_LEFT_REMOVE},
|
||||
* {@link SLIDE_RIGHT_REMOVE}, or {@link SLIDE_LEFT_REMOVE}.
|
||||
*/
|
||||
public void setRemoveMode(int mode) {
|
||||
mRemoveMode = mode;
|
||||
}
|
||||
|
||||
public int getRemoveMode() {
|
||||
return mRemoveMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable item removal without affecting remove mode.
|
||||
*/
|
||||
public void setRemoveEnabled(boolean enabled) {
|
||||
mRemoveEnabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isRemoveEnabled() {
|
||||
return mRemoveEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource id for the View that represents the drag
|
||||
* handle in a list item.
|
||||
*
|
||||
* @param id An android resource id.
|
||||
*/
|
||||
public void setDragHandleId(int id) {
|
||||
mDragHandleId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource id for the View that represents the fling
|
||||
* handle in a list item.
|
||||
*
|
||||
* @param id An android resource id.
|
||||
*/
|
||||
public void setFlingHandleId(int id) {
|
||||
mFlingHandleId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource id for the View that represents click
|
||||
* removal button.
|
||||
*
|
||||
* @param id An android resource id.
|
||||
*/
|
||||
public void setClickRemoveId(int id) {
|
||||
mClickRemoveId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets flags to restrict certain motions of the floating View
|
||||
* based on DragSortController settings (such as remove mode).
|
||||
* Starts the drag on the DragSortListView.
|
||||
*
|
||||
* @param position The list item position (includes headers).
|
||||
* @param deltaX Touch x-coord minus left edge of floating View.
|
||||
* @param deltaY Touch y-coord minus top edge of floating View.
|
||||
*
|
||||
* @return True if drag started, false otherwise.
|
||||
*/
|
||||
public boolean startDrag(int position, int deltaX, int deltaY) {
|
||||
|
||||
int dragFlags = 0;
|
||||
if (mSortEnabled && !mIsRemoving) {
|
||||
dragFlags |= DragSortListView.DRAG_POS_Y | DragSortListView.DRAG_NEG_Y;
|
||||
}
|
||||
if (mRemoveEnabled && mIsRemoving) {
|
||||
dragFlags |= DragSortListView.DRAG_POS_X;
|
||||
dragFlags |= DragSortListView.DRAG_NEG_X;
|
||||
}
|
||||
|
||||
mDragging = mDslv.startDrag(position - mDslv.getHeaderViewsCount(), dragFlags, deltaX,
|
||||
deltaY);
|
||||
return mDragging;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent ev) {
|
||||
if (!mDslv.isDragEnabled() || mDslv.listViewIntercepted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mDetector.onTouchEvent(ev);
|
||||
if (mRemoveEnabled && mDragging && mRemoveMode == FLING_REMOVE) {
|
||||
mFlingRemoveDetector.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mCurrX = (int) ev.getX();
|
||||
mCurrY = (int) ev.getY();
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mRemoveEnabled && mIsRemoving) {
|
||||
int x = mPositionX >= 0 ? mPositionX : -mPositionX;
|
||||
int removePoint = mDslv.getWidth() / 2;
|
||||
if (x > removePoint) {
|
||||
mDslv.stopDragWithVelocity(true, 0);
|
||||
}
|
||||
}
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mIsRemoving = false;
|
||||
mDragging = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides to provide fading when slide removal is enabled.
|
||||
*/
|
||||
@Override
|
||||
public void onDragFloatView(View floatView, Point position, Point touch) {
|
||||
|
||||
if (mRemoveEnabled && mIsRemoving) {
|
||||
mPositionX = position.x;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the position to start dragging based on the ACTION_DOWN
|
||||
* MotionEvent. This function simply calls
|
||||
* {@link #dragHandleHitPosition(MotionEvent)}. Override
|
||||
* to change drag handle behavior;
|
||||
* this function is called internally when an ACTION_DOWN
|
||||
* event is detected.
|
||||
*
|
||||
* @param ev The ACTION_DOWN MotionEvent.
|
||||
*
|
||||
* @return The list position to drag if a drag-init gesture is
|
||||
* detected; MISS if unsuccessful.
|
||||
*/
|
||||
public int startDragPosition(MotionEvent ev) {
|
||||
return dragHandleHitPosition(ev);
|
||||
}
|
||||
|
||||
public int startFlingPosition(MotionEvent ev) {
|
||||
return mRemoveMode == FLING_REMOVE ? flingHandleHitPosition(ev) : MISS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the touch of an item's drag handle (specified by
|
||||
* {@link #setDragHandleId(int)}), and returns that item's position
|
||||
* if a drag handle touch was detected.
|
||||
*
|
||||
* @param ev The ACTION_DOWN MotionEvent.
|
||||
|
||||
* @return The list position of the item whose drag handle was
|
||||
* touched; MISS if unsuccessful.
|
||||
*/
|
||||
public int dragHandleHitPosition(MotionEvent ev) {
|
||||
return viewIdHitPosition(ev, mDragHandleId);
|
||||
}
|
||||
|
||||
public int flingHandleHitPosition(MotionEvent ev) {
|
||||
return viewIdHitPosition(ev, mFlingHandleId);
|
||||
}
|
||||
|
||||
public int viewIdHitPosition(MotionEvent ev, int id) {
|
||||
final int x = (int) ev.getX();
|
||||
final int y = (int) ev.getY();
|
||||
|
||||
int touchPos = mDslv.pointToPosition(x, y); // includes headers/footers
|
||||
|
||||
final int numHeaders = mDslv.getHeaderViewsCount();
|
||||
final int numFooters = mDslv.getFooterViewsCount();
|
||||
final int count = mDslv.getCount();
|
||||
|
||||
// We're only interested if the touch was on an
|
||||
// item that's not a header or footer.
|
||||
if (touchPos != AdapterView.INVALID_POSITION && touchPos >= numHeaders
|
||||
&& touchPos < (count - numFooters)) {
|
||||
final View item = mDslv.getChildAt(touchPos - mDslv.getFirstVisiblePosition());
|
||||
final int rawX = (int) ev.getRawX();
|
||||
final int rawY = (int) ev.getRawY();
|
||||
|
||||
View dragBox = id == 0 ? item : (View) item.findViewById(id);
|
||||
if (dragBox != null) {
|
||||
dragBox.getLocationOnScreen(mTempLoc);
|
||||
|
||||
if (rawX > mTempLoc[0] && rawY > mTempLoc[1] &&
|
||||
rawX < mTempLoc[0] + dragBox.getWidth() &&
|
||||
rawY < mTempLoc[1] + dragBox.getHeight()) {
|
||||
|
||||
mItemX = item.getLeft();
|
||||
mItemY = item.getTop();
|
||||
|
||||
return touchPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MISS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent ev) {
|
||||
if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) {
|
||||
mClickRemoveHitPos = viewIdHitPosition(ev, mClickRemoveId);
|
||||
}
|
||||
|
||||
mHitPos = startDragPosition(ev);
|
||||
if (mHitPos != MISS && mDragInitMode == ON_DOWN) {
|
||||
startDrag(mHitPos, (int) ev.getX() - mItemX, (int) ev.getY() - mItemY);
|
||||
}
|
||||
|
||||
mIsRemoving = false;
|
||||
mCanDrag = true;
|
||||
mPositionX = 0;
|
||||
mFlingHitPos = startFlingPosition(ev);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
|
||||
final int x1 = (int) e1.getX();
|
||||
final int y1 = (int) e1.getY();
|
||||
final int x2 = (int) e2.getX();
|
||||
final int y2 = (int) e2.getY();
|
||||
final int deltaX = x2 - mItemX;
|
||||
final int deltaY = y2 - mItemY;
|
||||
|
||||
if (mCanDrag && !mDragging && (mHitPos != MISS || mFlingHitPos != MISS)) {
|
||||
if (mHitPos != MISS) {
|
||||
if (mDragInitMode == ON_DRAG && Math.abs(y2 - y1) > mTouchSlop && mSortEnabled) {
|
||||
startDrag(mHitPos, deltaX, deltaY);
|
||||
}
|
||||
else if (mDragInitMode != ON_DOWN && Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled)
|
||||
{
|
||||
mIsRemoving = true;
|
||||
startDrag(mFlingHitPos, deltaX, deltaY);
|
||||
}
|
||||
} else if (mFlingHitPos != MISS) {
|
||||
if (Math.abs(x2 - x1) > mTouchSlop && mRemoveEnabled) {
|
||||
mIsRemoving = true;
|
||||
startDrag(mFlingHitPos, deltaX, deltaY);
|
||||
} else if (Math.abs(y2 - y1) > mTouchSlop) {
|
||||
mCanDrag = false; // if started to scroll the list then
|
||||
// don't allow sorting nor fling-removing
|
||||
}
|
||||
}
|
||||
}
|
||||
// return whatever
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent e) {
|
||||
if (mHitPos != MISS && mDragInitMode == ON_LONG_PRESS) {
|
||||
mDslv.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
startDrag(mHitPos, mCurrX - mItemX, mCurrY - mItemY);
|
||||
}
|
||||
}
|
||||
|
||||
// complete the OnGestureListener interface
|
||||
@Override
|
||||
public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// complete the OnGestureListener interface
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent ev) {
|
||||
if (mRemoveEnabled && mRemoveMode == CLICK_REMOVE) {
|
||||
if (mClickRemoveHitPos != MISS) {
|
||||
mDslv.removeItem(mClickRemoveHitPos - mDslv.getHeaderViewsCount());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// complete the OnGestureListener interface
|
||||
@Override
|
||||
public void onShowPress(MotionEvent ev) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
private GestureDetector.OnGestureListener mFlingRemoveListener =
|
||||
new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public final boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
|
||||
float velocityY) {
|
||||
if (mRemoveEnabled && mIsRemoving) {
|
||||
int w = mDslv.getWidth();
|
||||
int minPos = w / 5;
|
||||
if (velocityX > mFlingSpeed) {
|
||||
if (mPositionX > -minPos) {
|
||||
mDslv.stopDragWithVelocity(true, velocityX);
|
||||
}
|
||||
} else if (velocityX < -mFlingSpeed) {
|
||||
if (mPositionX < minPos) {
|
||||
mDslv.stopDragWithVelocity(true, velocityX);
|
||||
}
|
||||
}
|
||||
mIsRemoving = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,241 +0,0 @@
|
|||
package com.mobeta.android.dslv;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.cursoradapter.widget.CursorAdapter;
|
||||
|
||||
|
||||
/**
|
||||
* A subclass of {@link android.widget.CursorAdapter} that provides
|
||||
* reordering of the elements in the Cursor based on completed
|
||||
* drag-sort operations. The reordering is a simple mapping of
|
||||
* list positions into Cursor positions (the Cursor is unchanged).
|
||||
* To persist changes made by drag-sorts, one can retrieve the
|
||||
* mapping with the {@link #getCursorPositions()} method, which
|
||||
* returns the reordered list of Cursor positions.
|
||||
*
|
||||
* An instance of this class is passed
|
||||
* to {@link DragSortListView#setAdapter(ListAdapter)} and, since
|
||||
* this class implements the {@link DragSortListView.DragSortListener}
|
||||
* interface, it is automatically set as the DragSortListener for
|
||||
* the DragSortListView instance.
|
||||
*/
|
||||
public abstract class DragSortCursorAdapter extends CursorAdapter implements DragSortListView.DragSortListener {
|
||||
|
||||
public static final int REMOVED = -1;
|
||||
|
||||
/**
|
||||
* Key is ListView position, value is Cursor position
|
||||
*/
|
||||
private SparseIntArray mListMapping = new SparseIntArray();
|
||||
|
||||
private ArrayList<Integer> mRemovedCursorPositions = new ArrayList<Integer>();
|
||||
|
||||
public DragSortCursorAdapter(Context context, Cursor c) {
|
||||
super(context, c);
|
||||
}
|
||||
|
||||
public DragSortCursorAdapter(Context context, Cursor c, boolean autoRequery) {
|
||||
super(context, c, autoRequery);
|
||||
}
|
||||
|
||||
public DragSortCursorAdapter(Context context, Cursor c, int flags) {
|
||||
super(context, c, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps Cursor and clears list-Cursor mapping.
|
||||
*
|
||||
* @see android.widget.CursorAdapter#swapCursor(android.database.Cursor)
|
||||
*/
|
||||
@Override
|
||||
public Cursor swapCursor(Cursor newCursor) {
|
||||
Cursor old = super.swapCursor(newCursor);
|
||||
resetMappings();
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes Cursor and clears list-Cursor mapping.
|
||||
*
|
||||
* @see android.widget.CursorAdapter#changeCursor(android.database.Cursor)
|
||||
*/
|
||||
@Override
|
||||
public void changeCursor(Cursor cursor) {
|
||||
super.changeCursor(cursor);
|
||||
resetMappings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets list-cursor mapping.
|
||||
*/
|
||||
public void reset() {
|
||||
resetMappings();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void resetMappings() {
|
||||
mListMapping.clear();
|
||||
mRemovedCursorPositions.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return super.getItem(mListMapping.get(position, position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return super.getItemId(mListMapping.get(position, position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getDropDownView(int position, View convertView, ViewGroup parent) {
|
||||
return super.getDropDownView(mListMapping.get(position, position), convertView, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
return super.getView(mListMapping.get(position, position), convertView, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* On drop, this updates the mapping between Cursor positions
|
||||
* and ListView positions. The Cursor is unchanged. Retrieve
|
||||
* the current mapping with {@link getCursorPositions()}.
|
||||
*
|
||||
* @see DragSortListView.DropListener#drop(int, int)
|
||||
*/
|
||||
@Override
|
||||
public void drop(int from, int to) {
|
||||
if (from != to) {
|
||||
int cursorFrom = mListMapping.get(from, from);
|
||||
|
||||
if (from > to) {
|
||||
for (int i = from; i > to; --i) {
|
||||
mListMapping.put(i, mListMapping.get(i - 1, i - 1));
|
||||
}
|
||||
} else {
|
||||
for (int i = from; i < to; ++i) {
|
||||
mListMapping.put(i, mListMapping.get(i + 1, i + 1));
|
||||
}
|
||||
}
|
||||
mListMapping.put(to, cursorFrom);
|
||||
|
||||
cleanMapping();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On remove, this updates the mapping between Cursor positions
|
||||
* and ListView positions. The Cursor is unchanged. Retrieve
|
||||
* the current mapping with {@link getCursorPositions()}.
|
||||
*
|
||||
* @see DragSortListView.RemoveListener#remove(int)
|
||||
*/
|
||||
@Override
|
||||
public void remove(int which) {
|
||||
int cursorPos = mListMapping.get(which, which);
|
||||
if (!mRemovedCursorPositions.contains(cursorPos)) {
|
||||
mRemovedCursorPositions.add(cursorPos);
|
||||
}
|
||||
|
||||
int newCount = getCount();
|
||||
for (int i = which; i < newCount; ++i) {
|
||||
mListMapping.put(i, mListMapping.get(i + 1, i + 1));
|
||||
}
|
||||
|
||||
mListMapping.delete(newCount);
|
||||
|
||||
cleanMapping();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing. Just completes DragSortListener interface.
|
||||
*/
|
||||
@Override
|
||||
public void drag(int from, int to) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unnecessary mappings from sparse array.
|
||||
*/
|
||||
private void cleanMapping() {
|
||||
ArrayList<Integer> toRemove = new ArrayList<Integer>();
|
||||
|
||||
int size = mListMapping.size();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (mListMapping.keyAt(i) == mListMapping.valueAt(i)) {
|
||||
toRemove.add(mListMapping.keyAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
size = toRemove.size();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
mListMapping.delete(toRemove.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return super.getCount() - mRemovedCursorPositions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cursor position mapped to by the provided list position
|
||||
* (given all previously handled drag-sort
|
||||
* operations).
|
||||
*
|
||||
* @param position List position
|
||||
*
|
||||
* @return The mapped-to Cursor position
|
||||
*/
|
||||
public int getCursorPosition(int position) {
|
||||
return mListMapping.get(position, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current order of Cursor positions presented by the
|
||||
* list.
|
||||
*/
|
||||
public ArrayList<Integer> getCursorPositions() {
|
||||
ArrayList<Integer> result = new ArrayList<Integer>();
|
||||
|
||||
for (int i = 0; i < getCount(); ++i) {
|
||||
result.add(mListMapping.get(i, i));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list position mapped to by the provided Cursor position.
|
||||
* If the provided Cursor position has been removed by a drag-sort,
|
||||
* this returns {@link #REMOVED}.
|
||||
*
|
||||
* @param cursorPosition A Cursor position
|
||||
* @return The mapped-to list position or REMOVED
|
||||
*/
|
||||
public int getListPosition(int cursorPosition) {
|
||||
if (mRemovedCursorPositions.contains(cursorPosition)) {
|
||||
return REMOVED;
|
||||
}
|
||||
|
||||
int index = mListMapping.indexOfValue(cursorPosition);
|
||||
if (index < 0) {
|
||||
return cursorPosition;
|
||||
} else {
|
||||
return mListMapping.keyAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
package com.mobeta.android.dslv;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Lightweight ViewGroup that wraps list items obtained from user's
|
||||
* ListAdapter. ItemView expects a single child that has a definite
|
||||
* height (i.e. the child's layout height is not MATCH_PARENT).
|
||||
* The width of
|
||||
* ItemView will always match the width of its child (that is,
|
||||
* the width MeasureSpec given to ItemView is passed directly
|
||||
* to the child, and the ItemView measured width is set to the
|
||||
* child's measured width). The height of ItemView can be anything;
|
||||
* the
|
||||
*
|
||||
*
|
||||
* The purpose of this class is to optimize slide
|
||||
* shuffle animations.
|
||||
*/
|
||||
public class DragSortItemView extends ViewGroup {
|
||||
|
||||
private int mGravity = Gravity.TOP;
|
||||
|
||||
public DragSortItemView(Context context) {
|
||||
super(context);
|
||||
|
||||
// always init with standard ListView layout params
|
||||
setLayoutParams(new AbsListView.LayoutParams(
|
||||
ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
|
||||
//setClipChildren(true);
|
||||
}
|
||||
|
||||
public void setGravity(int gravity) {
|
||||
mGravity = gravity;
|
||||
}
|
||||
|
||||
public int getGravity() {
|
||||
return mGravity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
final View child = getChildAt(0);
|
||||
|
||||
if (child == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mGravity == Gravity.TOP) {
|
||||
child.layout(0, 0, getMeasuredWidth(), child.getMeasuredHeight());
|
||||
} else {
|
||||
child.layout(0, getMeasuredHeight() - child.getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
|
||||
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
|
||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
|
||||
final View child = getChildAt(0);
|
||||
if (child == null) {
|
||||
setMeasuredDimension(0, width);
|
||||
return;
|
||||
}
|
||||
|
||||
if (child.isLayoutRequested()) {
|
||||
// Always let child be as tall as it wants.
|
||||
measureChild(child, widthMeasureSpec,
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
|
||||
}
|
||||
|
||||
if (heightMode == MeasureSpec.UNSPECIFIED) {
|
||||
ViewGroup.LayoutParams lp = getLayoutParams();
|
||||
|
||||
if (lp.height > 0) {
|
||||
height = lp.height;
|
||||
} else {
|
||||
height = child.getMeasuredHeight();
|
||||
}
|
||||
}
|
||||
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package com.mobeta.android.dslv;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.Checkable;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Lightweight ViewGroup that wraps list items obtained from user's
|
||||
* ListAdapter. ItemView expects a single child that has a definite
|
||||
* height (i.e. the child's layout height is not MATCH_PARENT).
|
||||
* The width of
|
||||
* ItemView will always match the width of its child (that is,
|
||||
* the width MeasureSpec given to ItemView is passed directly
|
||||
* to the child, and the ItemView measured width is set to the
|
||||
* child's measured width). The height of ItemView can be anything;
|
||||
* the
|
||||
*
|
||||
*
|
||||
* The purpose of this class is to optimize slide
|
||||
* shuffle animations.
|
||||
*/
|
||||
public class DragSortItemViewCheckable extends DragSortItemView implements Checkable {
|
||||
|
||||
public DragSortItemViewCheckable(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
View child = getChildAt(0);
|
||||
if (child instanceof Checkable)
|
||||
return ((Checkable) child).isChecked();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked) {
|
||||
View child = getChildAt(0);
|
||||
if (child instanceof Checkable)
|
||||
((Checkable) child).setChecked(checked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggle() {
|
||||
View child = getChildAt(0);
|
||||
if (child instanceof Checkable)
|
||||
((Checkable) child).toggle();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mobeta.android.dslv;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
// taken from v4 rev. 10 ResourceCursorAdapter.java
|
||||
|
||||
/**
|
||||
* Static library support version of the framework's {@link android.widget.ResourceCursorAdapter}.
|
||||
* Used to write apps that run on platforms prior to Android 3.0. When running
|
||||
* on Android 3.0 or above, this implementation is still used; it does not try
|
||||
* to switch to the framework's implementation. See the framework SDK
|
||||
* documentation for a class overview.
|
||||
*/
|
||||
public abstract class ResourceDragSortCursorAdapter extends DragSortCursorAdapter {
|
||||
private int mLayout;
|
||||
|
||||
private int mDropDownLayout;
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
/**
|
||||
* Constructor the enables auto-requery.
|
||||
*
|
||||
* @deprecated This option is discouraged, as it results in Cursor queries
|
||||
* being performed on the application's UI thread and thus can cause poor
|
||||
* responsiveness or even Application Not Responding errors. As an alternative,
|
||||
* use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}.
|
||||
*
|
||||
* @param context The context where the ListView associated with this adapter is running
|
||||
* @param layout resource identifier of a layout file that defines the views
|
||||
* for this list item. Unless you override them later, this will
|
||||
* define both the item views and the drop down views.
|
||||
*/
|
||||
@Deprecated
|
||||
public ResourceDragSortCursorAdapter(Context context, int layout, Cursor c) {
|
||||
super(context, c);
|
||||
mLayout = mDropDownLayout = layout;
|
||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with default behavior as per
|
||||
* {@link CursorAdapter#CursorAdapter(Context, Cursor, boolean)}; it is recommended
|
||||
* you not use this, but instead {@link #ResourceCursorAdapter(Context, int, Cursor, int)}.
|
||||
* When using this constructor, {@link #FLAG_REGISTER_CONTENT_OBSERVER}
|
||||
* will always be set.
|
||||
*
|
||||
* @param context The context where the ListView associated with this adapter is running
|
||||
* @param layout resource identifier of a layout file that defines the views
|
||||
* for this list item. Unless you override them later, this will
|
||||
* define both the item views and the drop down views.
|
||||
* @param c The cursor from which to get the data.
|
||||
* @param autoRequery If true the adapter will call requery() on the
|
||||
* cursor whenever it changes so the most recent
|
||||
* data is always displayed. Using true here is discouraged.
|
||||
*/
|
||||
public ResourceDragSortCursorAdapter(Context context, int layout, Cursor c, boolean autoRequery) {
|
||||
super(context, c, autoRequery);
|
||||
mLayout = mDropDownLayout = layout;
|
||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard constructor.
|
||||
*
|
||||
* @param context The context where the ListView associated with this adapter is running
|
||||
* @param layout Resource identifier of a layout file that defines the views
|
||||
* for this list item. Unless you override them later, this will
|
||||
* define both the item views and the drop down views.
|
||||
* @param c The cursor from which to get the data.
|
||||
* @param flags Flags used to determine the behavior of the adapter,
|
||||
* as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}.
|
||||
*/
|
||||
public ResourceDragSortCursorAdapter(Context context, int layout, Cursor c, int flags) {
|
||||
super(context, c, flags);
|
||||
mLayout = mDropDownLayout = layout;
|
||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflates view(s) from the specified XML file.
|
||||
*
|
||||
* @see android.widget.CursorAdapter#newView(android.content.Context,
|
||||
* android.database.Cursor, ViewGroup)
|
||||
*/
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return mInflater.inflate(mLayout, parent, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return mInflater.inflate(mDropDownLayout, parent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the layout resource of the item views.</p>
|
||||
*
|
||||
* @param layout the layout resources used to create item views
|
||||
*/
|
||||
public void setViewResource(int layout) {
|
||||
mLayout = layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the layout resource of the drop down views.</p>
|
||||
*
|
||||
* @param dropDownLayout the layout resources used to create drop down views
|
||||
*/
|
||||
public void setDropDownViewResource(int dropDownLayout) {
|
||||
mDropDownLayout = dropDownLayout;
|
||||
}
|
||||
}
|
|
@ -1,422 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mobeta.android.dslv;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ImageView;
|
||||
|
||||
// taken from sdk/sources/android-16/android/widget/SimpleCursorAdapter.java
|
||||
|
||||
/**
|
||||
* An easy adapter to map columns from a cursor to TextViews or ImageViews
|
||||
* defined in an XML file. You can specify which columns you want, which
|
||||
* views you want to display the columns, and the XML file that defines
|
||||
* the appearance of these views.
|
||||
*
|
||||
* Binding occurs in two phases. First, if a
|
||||
* {@link android.widget.SimpleCursorAdapter.ViewBinder} is available,
|
||||
* {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)}
|
||||
* is invoked. If the returned value is true, binding has occured. If the
|
||||
* returned value is false and the view to bind is a TextView,
|
||||
* {@link #setViewText(TextView, String)} is invoked. If the returned value
|
||||
* is false and the view to bind is an ImageView,
|
||||
* {@link #setViewImage(ImageView, String)} is invoked. If no appropriate
|
||||
* binding can be found, an {@link IllegalStateException} is thrown.
|
||||
*
|
||||
* If this adapter is used with filtering, for instance in an
|
||||
* {@link android.widget.AutoCompleteTextView}, you can use the
|
||||
* {@link android.widget.SimpleCursorAdapter.CursorToStringConverter} and the
|
||||
* {@link android.widget.FilterQueryProvider} interfaces
|
||||
* to get control over the filtering process. You can refer to
|
||||
* {@link #convertToString(android.database.Cursor)} and
|
||||
* {@link #runQueryOnBackgroundThread(CharSequence)} for more information.
|
||||
*/
|
||||
public class SimpleDragSortCursorAdapter extends ResourceDragSortCursorAdapter {
|
||||
/**
|
||||
* A list of columns containing the data to bind to the UI.
|
||||
* This field should be made private, so it is hidden from the SDK.
|
||||
* {@hide}
|
||||
*/
|
||||
protected int[] mFrom;
|
||||
/**
|
||||
* A list of View ids representing the views to which the data must be bound.
|
||||
* This field should be made private, so it is hidden from the SDK.
|
||||
* {@hide}
|
||||
*/
|
||||
protected int[] mTo;
|
||||
|
||||
private int mStringConversionColumn = -1;
|
||||
private CursorToStringConverter mCursorToStringConverter;
|
||||
private ViewBinder mViewBinder;
|
||||
|
||||
String[] mOriginalFrom;
|
||||
|
||||
/**
|
||||
* Constructor the enables auto-requery.
|
||||
*
|
||||
* @deprecated This option is discouraged, as it results in Cursor queries
|
||||
* being performed on the application's UI thread and thus can cause poor
|
||||
* responsiveness or even Application Not Responding errors. As an alternative,
|
||||
* use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}.
|
||||
*/
|
||||
@Deprecated
|
||||
public SimpleDragSortCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
|
||||
super(context, layout, c);
|
||||
mTo = to;
|
||||
mOriginalFrom = from;
|
||||
findColumns(c, from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard constructor.
|
||||
*
|
||||
* @param context The context where the ListView associated with this
|
||||
* SimpleListItemFactory is running
|
||||
* @param layout resource identifier of a layout file that defines the views
|
||||
* for this list item. The layout file should include at least
|
||||
* those named views defined in "to"
|
||||
* @param c The database cursor. Can be null if the cursor is not available yet.
|
||||
* @param from A list of column names representing the data to bind to the UI. Can be null
|
||||
* if the cursor is not available yet.
|
||||
* @param to The views that should display column in the "from" parameter.
|
||||
* These should all be TextViews. The first N views in this list
|
||||
* are given the values of the first N columns in the from
|
||||
* parameter. Can be null if the cursor is not available yet.
|
||||
* @param flags Flags used to determine the behavior of the adapter,
|
||||
* as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}.
|
||||
*/
|
||||
public SimpleDragSortCursorAdapter(Context context, int layout,
|
||||
Cursor c, String[] from, int[] to, int flags) {
|
||||
super(context, layout, c, flags);
|
||||
mTo = to;
|
||||
mOriginalFrom = from;
|
||||
findColumns(c, from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds all of the field names passed into the "to" parameter of the
|
||||
* constructor with their corresponding cursor columns as specified in the
|
||||
* "from" parameter.
|
||||
*
|
||||
* Binding occurs in two phases. First, if a
|
||||
* {@link android.widget.SimpleCursorAdapter.ViewBinder} is available,
|
||||
* {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)}
|
||||
* is invoked. If the returned value is true, binding has occured. If the
|
||||
* returned value is false and the view to bind is a TextView,
|
||||
* {@link #setViewText(TextView, String)} is invoked. If the returned value is
|
||||
* false and the view to bind is an ImageView,
|
||||
* {@link #setViewImage(ImageView, String)} is invoked. If no appropriate
|
||||
* binding can be found, an {@link IllegalStateException} is thrown.
|
||||
*
|
||||
* @throws IllegalStateException if binding cannot occur
|
||||
*
|
||||
* @see android.widget.CursorAdapter#bindView(android.view.View,
|
||||
* android.content.Context, android.database.Cursor)
|
||||
* @see #getViewBinder()
|
||||
* @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder)
|
||||
* @see #setViewImage(ImageView, String)
|
||||
* @see #setViewText(TextView, String)
|
||||
*/
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
final ViewBinder binder = mViewBinder;
|
||||
final int count = mTo.length;
|
||||
final int[] from = mFrom;
|
||||
final int[] to = mTo;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View v = view.findViewById(to[i]);
|
||||
if (v != null) {
|
||||
boolean bound = false;
|
||||
if (binder != null) {
|
||||
bound = binder.setViewValue(v, cursor, from[i]);
|
||||
}
|
||||
|
||||
if (!bound) {
|
||||
String text = cursor.getString(from[i]);
|
||||
if (text == null) {
|
||||
text = "";
|
||||
}
|
||||
|
||||
if (v instanceof TextView) {
|
||||
setViewText((TextView) v, text);
|
||||
} else if (v instanceof ImageView) {
|
||||
setViewImage((ImageView) v, text);
|
||||
} else {
|
||||
throw new IllegalStateException(v.getClass().getName() + " is not a " +
|
||||
" view that can be bounds by this SimpleCursorAdapter");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ViewBinder} used to bind data to views.
|
||||
*
|
||||
* @return a ViewBinder or null if the binder does not exist
|
||||
*
|
||||
* @see #bindView(android.view.View, android.content.Context, android.database.Cursor)
|
||||
* @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder)
|
||||
*/
|
||||
public ViewBinder getViewBinder() {
|
||||
return mViewBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the binder used to bind data to views.
|
||||
*
|
||||
* @param viewBinder the binder used to bind data to views, can be null to
|
||||
* remove the existing binder
|
||||
*
|
||||
* @see #bindView(android.view.View, android.content.Context, android.database.Cursor)
|
||||
* @see #getViewBinder()
|
||||
*/
|
||||
public void setViewBinder(ViewBinder viewBinder) {
|
||||
mViewBinder = viewBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by bindView() to set the image for an ImageView but only if
|
||||
* there is no existing ViewBinder or if the existing ViewBinder cannot
|
||||
* handle binding to an ImageView.
|
||||
*
|
||||
* By default, the value will be treated as an image resource. If the
|
||||
* value cannot be used as an image resource, the value is used as an
|
||||
* image Uri.
|
||||
*
|
||||
* Intended to be overridden by Adapters that need to filter strings
|
||||
* retrieved from the database.
|
||||
*
|
||||
* @param v ImageView to receive an image
|
||||
* @param value the value retrieved from the cursor
|
||||
*/
|
||||
public void setViewImage(ImageView v, String value) {
|
||||
try {
|
||||
v.setImageResource(Integer.parseInt(value));
|
||||
} catch (NumberFormatException nfe) {
|
||||
v.setImageURI(Uri.parse(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by bindView() to set the text for a TextView but only if
|
||||
* there is no existing ViewBinder or if the existing ViewBinder cannot
|
||||
* handle binding to a TextView.
|
||||
*
|
||||
* Intended to be overridden by Adapters that need to filter strings
|
||||
* retrieved from the database.
|
||||
*
|
||||
* @param v TextView to receive text
|
||||
* @param text the text to be set for the TextView
|
||||
*/
|
||||
public void setViewText(TextView v, String text) {
|
||||
v.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the column used to get a String representation
|
||||
* of the Cursor.
|
||||
*
|
||||
* @return a valid index in the current Cursor or -1
|
||||
*
|
||||
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||
* @see #setStringConversionColumn(int)
|
||||
* @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter)
|
||||
* @see #getCursorToStringConverter()
|
||||
*/
|
||||
public int getStringConversionColumn() {
|
||||
return mStringConversionColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the index of the column in the Cursor used to get a String
|
||||
* representation of that Cursor. The column is used to convert the
|
||||
* Cursor to a String only when the current CursorToStringConverter
|
||||
* is null.
|
||||
*
|
||||
* @param stringConversionColumn a valid index in the current Cursor or -1 to use the default
|
||||
* conversion mechanism
|
||||
*
|
||||
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||
* @see #getStringConversionColumn()
|
||||
* @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter)
|
||||
* @see #getCursorToStringConverter()
|
||||
*/
|
||||
public void setStringConversionColumn(int stringConversionColumn) {
|
||||
mStringConversionColumn = stringConversionColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the converter used to convert the filtering Cursor
|
||||
* into a String.
|
||||
*
|
||||
* @return null if the converter does not exist or an instance of
|
||||
* {@link android.widget.SimpleCursorAdapter.CursorToStringConverter}
|
||||
*
|
||||
* @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter)
|
||||
* @see #getStringConversionColumn()
|
||||
* @see #setStringConversionColumn(int)
|
||||
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||
*/
|
||||
public CursorToStringConverter getCursorToStringConverter() {
|
||||
return mCursorToStringConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the converter used to convert the filtering Cursor
|
||||
* into a String.
|
||||
*
|
||||
* @param cursorToStringConverter the Cursor to String converter, or
|
||||
* null to remove the converter
|
||||
*
|
||||
* @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter)
|
||||
* @see #getStringConversionColumn()
|
||||
* @see #setStringConversionColumn(int)
|
||||
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||
*/
|
||||
public void setCursorToStringConverter(CursorToStringConverter cursorToStringConverter) {
|
||||
mCursorToStringConverter = cursorToStringConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CharSequence representation of the specified Cursor as defined
|
||||
* by the current CursorToStringConverter. If no CursorToStringConverter
|
||||
* has been set, the String conversion column is used instead. If the
|
||||
* conversion column is -1, the returned String is empty if the cursor
|
||||
* is null or Cursor.toString().
|
||||
*
|
||||
* @param cursor the Cursor to convert to a CharSequence
|
||||
*
|
||||
* @return a non-null CharSequence representing the cursor
|
||||
*/
|
||||
@Override
|
||||
public CharSequence convertToString(Cursor cursor) {
|
||||
if (mCursorToStringConverter != null) {
|
||||
return mCursorToStringConverter.convertToString(cursor);
|
||||
} else if (mStringConversionColumn > -1) {
|
||||
return cursor.getString(mStringConversionColumn);
|
||||
}
|
||||
|
||||
return super.convertToString(cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a map from an array of strings to an array of column-id integers in cursor c.
|
||||
* If c is null, the array will be discarded.
|
||||
*
|
||||
* @param c the cursor to find the columns from
|
||||
* @param from the Strings naming the columns of interest
|
||||
*/
|
||||
private void findColumns(Cursor c, String[] from) {
|
||||
if (c != null) {
|
||||
int i;
|
||||
int count = from.length;
|
||||
if (mFrom == null || mFrom.length != count) {
|
||||
mFrom = new int[count];
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
mFrom[i] = c.getColumnIndexOrThrow(from[i]);
|
||||
}
|
||||
} else {
|
||||
mFrom = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor swapCursor(Cursor c) {
|
||||
// super.swapCursor() will notify observers before we have
|
||||
// a valid mapping, make sure we have a mapping before this
|
||||
// happens
|
||||
findColumns(c, mOriginalFrom);
|
||||
return super.swapCursor(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the cursor and change the column-to-view mappings at the same time.
|
||||
*
|
||||
* @param c The database cursor. Can be null if the cursor is not available yet.
|
||||
* @param from A list of column names representing the data to bind to the UI. Can be null
|
||||
* if the cursor is not available yet.
|
||||
* @param to The views that should display column in the "from" parameter.
|
||||
* These should all be TextViews. The first N views in this list
|
||||
* are given the values of the first N columns in the from
|
||||
* parameter. Can be null if the cursor is not available yet.
|
||||
*/
|
||||
public void changeCursorAndColumns(Cursor c, String[] from, int[] to) {
|
||||
mOriginalFrom = from;
|
||||
mTo = to;
|
||||
// super.changeCursor() will notify observers before we have
|
||||
// a valid mapping, make sure we have a mapping before this
|
||||
// happens
|
||||
findColumns(c, mOriginalFrom);
|
||||
super.changeCursor(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class can be used by external clients of SimpleCursorAdapter
|
||||
* to bind values fom the Cursor to views.
|
||||
*
|
||||
* You should use this class to bind values from the Cursor to views
|
||||
* that are not directly supported by SimpleCursorAdapter or to
|
||||
* change the way binding occurs for views supported by
|
||||
* SimpleCursorAdapter.
|
||||
*
|
||||
* @see SimpleCursorAdapter#bindView(android.view.View, android.content.Context, android.database.Cursor)
|
||||
* @see SimpleCursorAdapter#setViewImage(ImageView, String)
|
||||
* @see SimpleCursorAdapter#setViewText(TextView, String)
|
||||
*/
|
||||
public static interface ViewBinder {
|
||||
/**
|
||||
* Binds the Cursor column defined by the specified index to the specified view.
|
||||
*
|
||||
* When binding is handled by this ViewBinder, this method must return true.
|
||||
* If this method returns false, SimpleCursorAdapter will attempts to handle
|
||||
* the binding on its own.
|
||||
*
|
||||
* @param view the view to bind the data to
|
||||
* @param cursor the cursor to get the data from
|
||||
* @param columnIndex the column at which the data can be found in the cursor
|
||||
*
|
||||
* @return true if the data was bound to the view, false otherwise
|
||||
*/
|
||||
boolean setViewValue(View view, Cursor cursor, int columnIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class can be used by external clients of SimpleCursorAdapter
|
||||
* to define how the Cursor should be converted to a String.
|
||||
*
|
||||
* @see android.widget.CursorAdapter#convertToString(android.database.Cursor)
|
||||
*/
|
||||
public static interface CursorToStringConverter {
|
||||
/**
|
||||
* Returns a CharSequence representing the specified Cursor.
|
||||
*
|
||||
* @param cursor the cursor for which a CharSequence representation
|
||||
* is requested
|
||||
*
|
||||
* @return a non-null CharSequence representing the cursor
|
||||
*/
|
||||
CharSequence convertToString(Cursor cursor);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
package com.mobeta.android.dslv;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Color;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ImageView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Simple implementation of the FloatViewManager class. Uses list
|
||||
* items as they appear in the ListView to create the floating View.
|
||||
*/
|
||||
public class SimpleFloatViewManager implements DragSortListView.FloatViewManager {
|
||||
|
||||
private Bitmap mFloatBitmap;
|
||||
|
||||
private ImageView mImageView;
|
||||
|
||||
private int mFloatBGColor = Color.BLACK;
|
||||
|
||||
private ListView mListView;
|
||||
|
||||
public SimpleFloatViewManager(ListView lv) {
|
||||
mListView = lv;
|
||||
}
|
||||
|
||||
public void setBackgroundColor(int color) {
|
||||
mFloatBGColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* This simple implementation creates a Bitmap copy of the
|
||||
* list item currently shown at ListView <code>position</code>.
|
||||
*/
|
||||
@Override
|
||||
public View onCreateFloatView(int position) {
|
||||
// Guaranteed that this will not be null? I think so. Nope, got
|
||||
// a NullPointerException once...
|
||||
View v = mListView.getChildAt(position + mListView.getHeaderViewsCount() - mListView.getFirstVisiblePosition());
|
||||
|
||||
if (v == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
v.setPressed(false);
|
||||
|
||||
// Create a copy of the drawing cache so that it does not get
|
||||
// recycled by the framework when the list tries to clean up memory
|
||||
//v.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
|
||||
v.setDrawingCacheEnabled(true);
|
||||
mFloatBitmap = Bitmap.createBitmap(v.getDrawingCache());
|
||||
v.setDrawingCacheEnabled(false);
|
||||
|
||||
if (mImageView == null) {
|
||||
mImageView = new ImageView(mListView.getContext());
|
||||
}
|
||||
mImageView.setBackgroundColor(mFloatBGColor);
|
||||
mImageView.setPadding(0, 0, 0, 0);
|
||||
mImageView.setImageBitmap(mFloatBitmap);
|
||||
mImageView.setLayoutParams(new ViewGroup.LayoutParams(v.getWidth(), v.getHeight()));
|
||||
|
||||
return mImageView;
|
||||
}
|
||||
|
||||
/**
|
||||
* This does nothing
|
||||
*/
|
||||
@Override
|
||||
public void onDragFloatView(View floatView, Point position, Point touch) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the Bitmap from the ImageView created in
|
||||
* onCreateFloatView() and tells the system to recycle it.
|
||||
*/
|
||||
@Override
|
||||
public void onDestroyFloatView(View floatView) {
|
||||
((ImageView) floatView).setImageDrawable(null);
|
||||
|
||||
mFloatBitmap.recycle();
|
||||
mFloatBitmap = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="DragSortListView">
|
||||
<attr name="collapsed_height" format="dimension" />
|
||||
<attr name="drag_scroll_start" format="float" />
|
||||
<attr name="max_drag_scroll_speed" format="float" />
|
||||
<attr name="float_background_color" format="color" />
|
||||
<attr name="remove_mode">
|
||||
<enum name="clickRemove" value="0" />
|
||||
<enum name="flingRemove" value="1" />
|
||||
</attr>
|
||||
<attr name="track_drag_sort" format="boolean"/>
|
||||
<attr name="float_alpha" format="float"/>
|
||||
<attr name="slide_shuffle_speed" format="float"/>
|
||||
<attr name="remove_animation_duration" format="integer"/>
|
||||
<attr name="drop_animation_duration" format="integer"/>
|
||||
<attr name="drag_enabled" format="boolean" />
|
||||
<attr name="sort_enabled" format="boolean" />
|
||||
<attr name="remove_enabled" format="boolean" />
|
||||
<attr name="drag_start_mode">
|
||||
<enum name="onDown" value="0" />
|
||||
<enum name="onMove" value="1" />
|
||||
<enum name="onLongPress" value="2"/>
|
||||
</attr>
|
||||
<attr name="drag_handle_id" format="integer" />
|
||||
<attr name="fling_handle_id" format="integer" />
|
||||
<attr name="click_remove_id" format="integer" />
|
||||
<attr name="use_default_controller" format="boolean" />
|
||||
</declare-styleable>
|
||||
</resources>
|
|
@ -22,11 +22,10 @@ val CLIENT_VERSION = SubsonicAPIVersions.V1_16_0
|
|||
const val CLIENT_ID = "test-client"
|
||||
|
||||
val dateFormat by lazy(
|
||||
LazyThreadSafetyMode.NONE,
|
||||
{
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
|
||||
}
|
||||
)
|
||||
LazyThreadSafetyMode.NONE
|
||||
) {
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
|
||||
}
|
||||
|
||||
fun MockWebServerRule.enqueueResponse(resourceName: String) {
|
||||
mockWebServer.enqueueResponse(resourceName)
|
||||
|
|
|
@ -42,6 +42,7 @@ import retrofit2.Call
|
|||
* Special wrapper for [SubsonicAPIDefinition] that checks if [currentApiVersion] is suitable
|
||||
* for this call.
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
internal class ApiVersionCheckWrapper(
|
||||
val api: SubsonicAPIDefinition,
|
||||
var currentApiVersion: SubsonicAPIVersions
|
||||
|
|
|
@ -183,7 +183,7 @@ class SubsonicAPIClient(
|
|||
this.addInterceptor(loggingInterceptor)
|
||||
}
|
||||
|
||||
@SuppressWarnings("TrustAllX509TrustManager")
|
||||
@SuppressWarnings("TrustAllX509TrustManager", "EmptyFunctionBlock")
|
||||
private fun OkHttpClient.Builder.allowSelfSignedCertificates() {
|
||||
val trustManager = object : X509TrustManager {
|
||||
override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.lang.NumberFormatException
|
|||
/**
|
||||
* Subsonic REST API versions.
|
||||
*/
|
||||
@Suppress("MagicNumber", "ComplexMethod", "ReturnCount", "ThrowsCount")
|
||||
@JsonDeserialize(using = SubsonicAPIVersions.Companion.SubsonicAPIVersionsDeserializer::class)
|
||||
enum class SubsonicAPIVersions(val subsonicVersions: String, val restApiVersion: String) {
|
||||
V1_1_0("3.8", "1.1.0"),
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
|||
/**
|
||||
* Common API errors.
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
@JsonDeserialize(using = SubsonicError.Companion.SubsonicErrorDeserializer::class)
|
||||
sealed class SubsonicError(val code: Int) {
|
||||
data class Generic(val message: String) : SubsonicError(0)
|
||||
|
|
|
@ -63,6 +63,7 @@ class VersionAwareJacksonConverterFactory(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("SwallowedException")
|
||||
class VersionAwareResponseBodyConverter<T> (
|
||||
private val notifier: (SubsonicAPIVersions) -> Unit = {},
|
||||
private val adapter: ObjectReader
|
||||
|
|
|
@ -11,6 +11,7 @@ fun String.toHexBytes(): String = this.toByteArray().toHexBytes()
|
|||
/**
|
||||
* Converts given [ByteArray] to corresponding hex chars representation.
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
fun ByteArray.toHexBytes(): String {
|
||||
val hexChars = CharArray(this.size * 2)
|
||||
for (j in 0..this.lastIndex) {
|
||||
|
|
|
@ -38,6 +38,7 @@ enum class AlbumListType(val typeName: String) {
|
|||
else -> throw IllegalArgumentException("Unknown type: $typeName")
|
||||
}
|
||||
|
||||
@Suppress("UnusedPrivateMember") // Used in the tests
|
||||
private operator fun String.contains(other: String) = this.equals(other, true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.moire.ultrasonic.api.subsonic.SubsonicError
|
|||
*
|
||||
* [responseHttpCode] will be there always.
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
class StreamResponse(
|
||||
val stream: InputStream? = null,
|
||||
val apiError: SubsonicError? = null,
|
||||
|
|
|
@ -31,6 +31,7 @@ ext.versions = [
|
|||
twitterSerial : "0.1.6",
|
||||
koin : "2.2.2",
|
||||
picasso : "2.71828",
|
||||
sortListView : "1.0.1",
|
||||
|
||||
junit4 : "4.13.2",
|
||||
junit5 : "5.7.1",
|
||||
|
@ -89,6 +90,7 @@ ext.other = [
|
|||
dexter : "com.karumi:dexter:$versions.dexter",
|
||||
timber : "com.jakewharton.timber:timber:$versions.timber",
|
||||
fastScroll : "com.simplecityapps:recyclerview-fastscroll:$versions.fastScroll",
|
||||
sortListView : "com.github.tzugen:drag-sort-listview:$versions.sortListView",
|
||||
]
|
||||
|
||||
ext.testing = [
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues></ManuallySuppressedIssues>
|
||||
<CurrentIssues>
|
||||
<ID>ComplexMethod:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$@JvmStatic @Throws(IllegalArgumentException::class) fun getClosestKnownClientApiVersion(apiVersion: String): SubsonicAPIVersions</ID>
|
||||
<ID>EmptyFunctionBlock:SubsonicAPIClient.kt$SubsonicAPIClient.<no name provided>${}</ID>
|
||||
<ID>MagicNumber:PasswordExt.kt$0xFF</ID>
|
||||
<ID>MagicNumber:PasswordExt.kt$4</ID>
|
||||
<ID>MagicNumber:PasswordMD5Interceptor.kt$PasswordMD5Interceptor$16</ID>
|
||||
<ID>MagicNumber:StreamResponse.kt$StreamResponse$200</ID>
|
||||
<ID>MagicNumber:StreamResponse.kt$StreamResponse$300</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$10</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$11</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$12</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$13</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$14</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$15</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$16</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$3</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$4</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$5</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$6</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$7</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$8</ID>
|
||||
<ID>MagicNumber:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$9</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.Companion$10</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.Companion$20</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.Companion$30</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.Companion$40</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.Companion$41</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.Companion$50</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.Companion$60</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.Companion$70</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.IncompatibleClientProtocolVersion$20</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.IncompatibleServerProtocolVersion$30</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.RequestedDataWasNotFound$70</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.RequiredParamMissing$10</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.TokenAuthNotSupportedForLDAP$41</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.TrialPeriodIsOver$60</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.UserNotAuthorizedForOperation$50</ID>
|
||||
<ID>MagicNumber:SubsonicError.kt$SubsonicError.WrongUsernameOrPassword$40</ID>
|
||||
<ID>ReturnCount:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$@JvmStatic @Throws(IllegalArgumentException::class) fun getClosestKnownClientApiVersion(apiVersion: String): SubsonicAPIVersions</ID>
|
||||
<ID>SwallowedException:VersionAwareJacksonConverterFactory.kt$VersionAwareJacksonConverterFactory.VersionAwareResponseBodyConverter$catch (e: IllegalArgumentException) { // no-op }</ID>
|
||||
<ID>ThrowsCount:SubsonicAPIVersions.kt$SubsonicAPIVersions.Companion$@JvmStatic @Throws(IllegalArgumentException::class) fun getClosestKnownClientApiVersion(apiVersion: String): SubsonicAPIVersions</ID>
|
||||
<ID>TooManyFunctions:ApiVersionCheckWrapper.kt$ApiVersionCheckWrapper : SubsonicAPIDefinition</ID>
|
||||
<ID>UnusedPrivateMember:AlbumListType.kt$AlbumListType.Companion$private operator fun String.contains(other: String)</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
|
@ -1,158 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues></ManuallySuppressedIssues>
|
||||
<CurrentIssues>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun areFieldsChanged(): Boolean</ID>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun finishActivity()</ID>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun getFields(): Boolean</ID>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun setFields()</ID>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun testConnection()</ID>
|
||||
<ID>CommentOverPrivateFunction:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile()</ID>
|
||||
<ID>CommentOverPrivateFunction:FileLoggerTree.kt$FileLoggerTree$ private fun getNumberedFile(next: Boolean)</ID>
|
||||
<ID>CommentOverPrivateFunction:MediaPlayerService.kt$MediaPlayerService$ private fun buildForegroundNotification( playerState: PlayerState, currentPlaying: DownloadFile? ): Notification</ID>
|
||||
<ID>CommentOverPrivateFunction:RESTMusicService.kt$RESTMusicService$ @Throws(Exception::class) private fun search2( criteria: SearchCriteria ): SearchResult</ID>
|
||||
<ID>CommentOverPrivateFunction:RESTMusicService.kt$RESTMusicService$ @Throws(Exception::class) private fun searchOld( criteria: SearchCriteria ): SearchResult</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerRowAdapter.kt$ServerRowAdapter$ private fun popupMenuItemClick(menuItem: MenuItem, position: Int): Boolean</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerRowAdapter.kt$ServerRowAdapter$ private fun serverMenuClick(view: View, position: Int)</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSelectorFragment.kt$ServerSelectorFragment$ private fun editServer(index: Int)</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSelectorFragment.kt$ServerSelectorFragment$ private fun onServerDeleted(index: Int)</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSelectorFragment.kt$ServerSelectorFragment$ private fun setActiveServer(index: Int)</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSettingsModel.kt$ServerSettingsModel$ private fun loadServerSettingFromPreferences( preferenceId: Int, serverId: Int, settings: SharedPreferences ): ServerSetting?</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSettingsModel.kt$ServerSettingsModel$ private suspend fun areIndexesMissing(): Boolean</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSettingsModel.kt$ServerSettingsModel$ private suspend fun reindexSettings()</ID>
|
||||
<ID>ComplexCondition:DownloadHandler.kt$DownloadHandler.<no name provided>$!append && !playNext && !unpin && !background</ID>
|
||||
<ID>ComplexCondition:FilePickerAdapter.kt$FilePickerAdapter$currentDirectory.absolutePath == "/" || currentDirectory.absolutePath == "/storage" || currentDirectory.absolutePath == "/storage/emulated" || currentDirectory.absolutePath == "/mnt"</ID>
|
||||
<ID>ComplexCondition:LocalMediaPlayer.kt$LocalMediaPlayer$Util.getGaplessPlaybackPreference() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && ( playerState === PlayerState.STARTED || playerState === PlayerState.PAUSED )</ID>
|
||||
<ID>ComplexCondition:SongView.kt$SongView$TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo && Util.getVideoPlayerType() !== VideoPlayerType.FLASH</ID>
|
||||
<ID>ComplexMethod:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID>
|
||||
<ID>ComplexMethod:FilePickerAdapter.kt$FilePickerAdapter$private fun fileLister(currentDirectory: File)</ID>
|
||||
<ID>ComplexMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean)</ID>
|
||||
<ID>ComplexMethod:TrackCollectionFragment.kt$TrackCollectionFragment$private fun enableButtons()</ID>
|
||||
<ID>ComplexMethod:TrackCollectionFragment.kt$TrackCollectionFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)</ID>
|
||||
<ID>EmptyCatchBlock:LocalMediaPlayer.kt$LocalMediaPlayer${ }</ID>
|
||||
<ID>EmptyDefaultConstructor:VideoPlayer.kt$VideoPlayer$()</ID>
|
||||
<ID>EmptyFunctionBlock:SongView.kt$SongView${}</ID>
|
||||
<ID>FunctionNaming:ThemeChangedEventDistributor.kt$ThemeChangedEventDistributor$fun RaiseThemeChangedEvent()</ID>
|
||||
<ID>ImplicitDefaultLocale:DownloadFile.kt$DownloadFile$String.format("DownloadFile (%s)", song)</ID>
|
||||
<ID>ImplicitDefaultLocale:DownloadFile.kt$DownloadFile.DownloadTask$String.format("Download of '%s' was cancelled", song)</ID>
|
||||
<ID>ImplicitDefaultLocale:DownloadFile.kt$DownloadFile.DownloadTask$String.format("DownloadTask (%s)", song)</ID>
|
||||
<ID>ImplicitDefaultLocale:EditServerFragment.kt$EditServerFragment.<no name provided>$String.format( "%s %s", resources.getString(R.string.settings_connection_failure), getErrorMessage(error) )</ID>
|
||||
<ID>ImplicitDefaultLocale:FileLoggerTree.kt$FileLoggerTree$String.format("Failed to write log to %s", file)</ID>
|
||||
<ID>ImplicitDefaultLocale:FileLoggerTree.kt$FileLoggerTree$String.format("Log file rotated, logging into file %s", file?.name)</ID>
|
||||
<ID>ImplicitDefaultLocale:FileLoggerTree.kt$FileLoggerTree$String.format("Logging into file %s", file?.name)</ID>
|
||||
<ID>ImplicitDefaultLocale:LocalMediaPlayer.kt$LocalMediaPlayer.BufferTask$String.format("BufferTask (%s)", downloadFile)</ID>
|
||||
<ID>ImplicitDefaultLocale:LocalMediaPlayer.kt$LocalMediaPlayer.CheckCompletionTask$String.format("CheckCompletionTask (%s)", downloadFile)</ID>
|
||||
<ID>ImplicitDefaultLocale:ShareHandler.kt$ShareHandler$String.format("%d:%s", timeSpanAmount, timeSpanType)</ID>
|
||||
<ID>ImplicitDefaultLocale:ShareHandler.kt$ShareHandler.<no name provided>$String.format("%s\n\n%s", Util.getShareGreeting(context), result.url)</ID>
|
||||
<ID>ImplicitDefaultLocale:SongView.kt$SongView$String.format("%02d.", trackNumber)</ID>
|
||||
<ID>ImplicitDefaultLocale:SongView.kt$SongView$String.format("%s ", bitRate)</ID>
|
||||
<ID>ImplicitDefaultLocale:SongView.kt$SongView$String.format("%s > %s", suffix, transcodedSuffix)</ID>
|
||||
<ID>LargeClass:MediaPlayerService.kt$MediaPlayerService : Service</ID>
|
||||
<ID>LargeClass:RESTMusicService.kt$RESTMusicService : MusicService</ID>
|
||||
<ID>LargeClass:TrackCollectionFragment.kt$TrackCollectionFragment : Fragment</ID>
|
||||
<ID>LongMethod:ArtistListFragment.kt$ArtistListFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
|
||||
<ID>LongMethod:ArtistListFragment.kt$ArtistListFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean</ID>
|
||||
<ID>LongMethod:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID>
|
||||
<ID>LongMethod:EditServerFragment.kt$EditServerFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
|
||||
<ID>LongMethod:FilePickerAdapter.kt$FilePickerAdapter$private fun fileLister(currentDirectory: File)</ID>
|
||||
<ID>LongMethod:LocalMediaPlayer.kt$LocalMediaPlayer$@Synchronized private fun doPlay(downloadFile: DownloadFile, position: Int, start: Boolean)</ID>
|
||||
<ID>LongMethod:MediaPlayerService.kt$MediaPlayerService$private fun updateMediaSession(currentPlaying: DownloadFile?, playerState: PlayerState)</ID>
|
||||
<ID>LongMethod:NavigationActivity.kt$NavigationActivity$override fun onCreate(savedInstanceState: Bundle?)</ID>
|
||||
<ID>LongMethod:ShareHandler.kt$ShareHandler$private fun showDialog( fragment: Fragment, shareDetails: ShareDetails, swipe: SwipeRefreshLayout?, cancellationToken: CancellationToken )</ID>
|
||||
<ID>LongMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean)</ID>
|
||||
<ID>LongMethod:TrackCollectionFragment.kt$TrackCollectionFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID>
|
||||
<ID>LongMethod:TrackCollectionFragment.kt$TrackCollectionFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
|
||||
<ID>LongMethod:TrackCollectionFragment.kt$TrackCollectionFragment$private fun updateDisplay(refresh: Boolean)</ID>
|
||||
<ID>LongMethod:TrackCollectionFragment.kt$TrackCollectionFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)</ID>
|
||||
<ID>LongParameterList:DownloadHandler.kt$DownloadHandler$( fragment: Fragment, append: Boolean, save: Boolean, autoPlay: Boolean, playNext: Boolean, shuffle: Boolean, songs: List<MusicDirectory.Entry?> )</ID>
|
||||
<ID>LongParameterList:DownloadHandler.kt$DownloadHandler$( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID>
|
||||
<ID>LongParameterList:DownloadHandler.kt$DownloadHandler$( fragment: Fragment, id: String, name: String?, save: Boolean, append: Boolean, autoplay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean )</ID>
|
||||
<ID>LongParameterList:DownloadHandler.kt$DownloadHandler$( fragment: Fragment, id: String?, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID>
|
||||
<ID>LongParameterList:ServerRowAdapter.kt$ServerRowAdapter$( private var context: Context, private var data: Array<ServerSetting>, private val model: ServerSettingsModel, private val activeServerProvider: ActiveServerProvider, private val manageMode: Boolean, private val serverDeletedCallback: ((Int) -> Unit), private val serverEditRequestedCallback: ((Int) -> Unit) )</ID>
|
||||
<ID>MagicNumber:ActiveServerProvider.kt$ActiveServerProvider$8192</ID>
|
||||
<ID>MagicNumber:AudioFocusHandler.kt$AudioFocusHandler$0.1f</ID>
|
||||
<ID>MagicNumber:DownloadFile.kt$DownloadFile$100</ID>
|
||||
<ID>MagicNumber:DownloadFile.kt$DownloadFile.DownloadTask$10</ID>
|
||||
<ID>MagicNumber:DownloadFile.kt$DownloadFile.DownloadTask$1000L</ID>
|
||||
<ID>MagicNumber:DownloadFile.kt$DownloadFile.DownloadTask$60</ID>
|
||||
<ID>MagicNumber:DownloadHandler.kt$DownloadHandler$500</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$100</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$3</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$4</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$5</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$6</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$7</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer$100</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer$1000</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.<no name provided>$1000</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.<no name provided>$60000</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.BufferTask$100000</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.BufferTask$1000L</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.BufferTask$1024L</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.BufferTask$8</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.BufferTask$86400L</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.BufferTask$8L</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.CheckCompletionTask$5000L</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$50L</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$100</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$1000</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$256</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$3</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$4</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService.Companion$19</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService.Companion$50L</ID>
|
||||
<ID>MagicNumber:RESTMusicService.kt$RESTMusicService$206</ID>
|
||||
<ID>MagicNumber:RESTMusicService.kt$RESTMusicService$5</ID>
|
||||
<ID>MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10</ID>
|
||||
<ID>MagicNumber:SongView.kt$SongView$3</ID>
|
||||
<ID>MagicNumber:SongView.kt$SongView$4</ID>
|
||||
<ID>MagicNumber:SongView.kt$SongView$60</ID>
|
||||
<ID>MagicNumber:TrackCollectionFragment.kt$TrackCollectionFragment$10</ID>
|
||||
<ID>NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID>
|
||||
<ID>NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID>
|
||||
<ID>NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID>
|
||||
<ID>ReturnCount:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting</ID>
|
||||
<ID>ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String</ID>
|
||||
<ID>ReturnCount:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile()</ID>
|
||||
<ID>ReturnCount:MediaPlayerService.kt$MediaPlayerService$private fun generateAction(context: Context, requestCode: Int): NotificationCompat.Action?</ID>
|
||||
<ID>ReturnCount:RESTMusicService.kt$RESTMusicService$@Throws(Exception::class) override fun getAvatar( username: String?, size: Int, saveToFile: Boolean, highQuality: Boolean ): Bitmap?</ID>
|
||||
<ID>ReturnCount:RESTMusicService.kt$RESTMusicService$@Throws(Exception::class) override fun getCoverArt( entry: MusicDirectory.Entry?, size: Int, saveToFile: Boolean, highQuality: Boolean ): Bitmap?</ID>
|
||||
<ID>ReturnCount:ServerRowAdapter.kt$ServerRowAdapter$ private fun popupMenuItemClick(menuItem: MenuItem, position: Int): Boolean</ID>
|
||||
<ID>ReturnCount:TrackCollectionFragment.kt$TrackCollectionFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID>
|
||||
<ID>ReturnCount:TrackCollectionFragment.kt$TrackCollectionFragment$override fun onOptionsItemSelected(item: MenuItem): Boolean</ID>
|
||||
<ID>SpreadOperator:MediaPlayerService.kt$MediaPlayerService$(*compactActions)</ID>
|
||||
<ID>SwallowedException:DownloadFile.kt$DownloadFile$catch (e: Exception) { Timber.w("Failed to set last-modified date on %s", file) }</ID>
|
||||
<ID>SwallowedException:DownloadFile.kt$DownloadFile$catch (ex: IOException) { Timber.w("Failed to rename file %s to %s", completeFile, saveFile) }</ID>
|
||||
<ID>SwallowedException:LocalMediaPlayer.kt$LocalMediaPlayer$catch (e: Throwable) { // Froyo or lower }</ID>
|
||||
<ID>SwallowedException:LocalMediaPlayer.kt$LocalMediaPlayer$catch (e: Throwable) { }</ID>
|
||||
<ID>SwallowedException:MediaPlayerService.kt$MediaPlayerService$catch (x: IndexOutOfBoundsException) { // Ignored }</ID>
|
||||
<ID>SwallowedException:NavigationActivity.kt$NavigationActivity$catch (e: Resources.NotFoundException) { destination.id.toString() }</ID>
|
||||
<ID>ThrowsCount:ApiCallResponseChecker.kt$ApiCallResponseChecker.Companion$@Throws(SubsonicRESTException::class, IOException::class) fun checkResponseSuccessful(response: Response<out SubsonicResponse>)</ID>
|
||||
<ID>TooGenericExceptionCaught:ArtistListModel.kt$ArtistListModel$exception: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:DownloadFile.kt$DownloadFile$e: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:DownloadFile.kt$DownloadFile.DownloadTask$x: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:FileLoggerTree.kt$FileLoggerTree$x: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer$e: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer$ex: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer$exception: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer$x: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$e: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$e: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$x: IndexOutOfBoundsException</ID>
|
||||
<ID>TooGenericExceptionCaught:SongView.kt$SongView$e: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:SubsonicUncaughtExceptionHandler.kt$SubsonicUncaughtExceptionHandler$x: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:VideoPlayer.kt$VideoPlayer$e: Exception</ID>
|
||||
<ID>TooGenericExceptionThrown:DownloadFile.kt$DownloadFile.DownloadTask$throw Exception(String.format("Download of '%s' was cancelled", song))</ID>
|
||||
<ID>TooManyFunctions:LocalMediaPlayer.kt$LocalMediaPlayer</ID>
|
||||
<ID>TooManyFunctions:MediaPlayerService.kt$MediaPlayerService : Service</ID>
|
||||
<ID>TooManyFunctions:RESTMusicService.kt$RESTMusicService : MusicService</ID>
|
||||
<ID>TooManyFunctions:TrackCollectionFragment.kt$TrackCollectionFragment : Fragment</ID>
|
||||
<ID>TopLevelPropertyNaming:SubsonicUncaughtExceptionHandler.kt$private const val filename = "ultrasonic-stacktrace.txt"</ID>
|
||||
<ID>UnusedPrivateMember:RESTMusicService.kt$RESTMusicService.Companion$private const val INDEXES_FOLDER_STORAGE_NAME = "indexes_folder"</ID>
|
||||
<ID>UselessCallOnNotNull:FileLoggerTree.kt$FileLoggerTree$fileList.isNullOrEmpty()</ID>
|
||||
<ID>UselessCallOnNotNull:FileLoggerTree.kt$FileLoggerTree.Companion$fileList.isNullOrEmpty()</ID>
|
||||
<ID>UtilityClassWithPublicConstructor:CommunicationErrorHandler.kt$CommunicationErrorHandler</ID>
|
||||
<ID>UtilityClassWithPublicConstructor:FragmentTitle.kt$FragmentTitle</ID>
|
||||
<ID>VariableNaming:SelectMusicFolderView.kt$SelectMusicFolderView$private val MENU_GROUP_MUSIC_FOLDER = 10</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
|
@ -2,24 +2,6 @@
|
|||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues></ManuallySuppressedIssues>
|
||||
<CurrentIssues>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun areFieldsChanged(): Boolean</ID>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun finishActivity()</ID>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun getFields(): Boolean</ID>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun setFields()</ID>
|
||||
<ID>CommentOverPrivateFunction:EditServerFragment.kt$EditServerFragment$ private fun testConnection()</ID>
|
||||
<ID>CommentOverPrivateFunction:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile()</ID>
|
||||
<ID>CommentOverPrivateFunction:FileLoggerTree.kt$FileLoggerTree$ private fun getNumberedFile(next: Boolean)</ID>
|
||||
<ID>CommentOverPrivateFunction:MediaPlayerService.kt$MediaPlayerService$ private fun buildForegroundNotification( playerState: PlayerState, currentPlaying: DownloadFile? ): Notification</ID>
|
||||
<ID>CommentOverPrivateFunction:RESTMusicService.kt$RESTMusicService$ @Throws(Exception::class) private fun search2( criteria: SearchCriteria ): SearchResult</ID>
|
||||
<ID>CommentOverPrivateFunction:RESTMusicService.kt$RESTMusicService$ @Throws(Exception::class) private fun searchOld( criteria: SearchCriteria ): SearchResult</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerRowAdapter.kt$ServerRowAdapter$ private fun popupMenuItemClick(menuItem: MenuItem, position: Int): Boolean</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerRowAdapter.kt$ServerRowAdapter$ private fun serverMenuClick(view: View, position: Int)</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSelectorFragment.kt$ServerSelectorFragment$ private fun editServer(index: Int)</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSelectorFragment.kt$ServerSelectorFragment$ private fun onServerDeleted(index: Int)</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSelectorFragment.kt$ServerSelectorFragment$ private fun setActiveServer(index: Int)</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSettingsModel.kt$ServerSettingsModel$ private fun loadServerSettingFromPreferences( preferenceId: Int, serverId: Int, settings: SharedPreferences ): ServerSetting?</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSettingsModel.kt$ServerSettingsModel$ private suspend fun areIndexesMissing(): Boolean</ID>
|
||||
<ID>CommentOverPrivateFunction:ServerSettingsModel.kt$ServerSettingsModel$ private suspend fun reindexSettings()</ID>
|
||||
<ID>ComplexCondition:DownloadHandler.kt$DownloadHandler.<no name provided>$!append && !playNext && !unpin && !background</ID>
|
||||
<ID>ComplexCondition:FilePickerAdapter.kt$FilePickerAdapter$currentDirectory.absolutePath == "/" || currentDirectory.absolutePath == "/storage" || currentDirectory.absolutePath == "/storage/emulated" || currentDirectory.absolutePath == "/mnt"</ID>
|
||||
<ID>ComplexCondition:LocalMediaPlayer.kt$LocalMediaPlayer$Util.getGaplessPlaybackPreference() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && ( playerState === PlayerState.STARTED || playerState === PlayerState.PAUSED )</ID>
|
||||
|
@ -47,11 +29,8 @@
|
|||
<ID>ImplicitDefaultLocale:SongView.kt$SongView$String.format("%02d.", trackNumber)</ID>
|
||||
<ID>ImplicitDefaultLocale:SongView.kt$SongView$String.format("%s ", bitRate)</ID>
|
||||
<ID>ImplicitDefaultLocale:SongView.kt$SongView$String.format("%s > %s", suffix, transcodedSuffix)</ID>
|
||||
<ID>LargeClass:MediaPlayerService.kt$MediaPlayerService : Service</ID>
|
||||
<ID>LargeClass:RESTMusicService.kt$RESTMusicService : MusicService</ID>
|
||||
<ID>LargeClass:TrackCollectionFragment.kt$TrackCollectionFragment : Fragment</ID>
|
||||
<ID>LongMethod:ArtistListFragment.kt$ArtistListFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
|
||||
<ID>LongMethod:ArtistListFragment.kt$ArtistListFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean</ID>
|
||||
<ID>LongMethod:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID>
|
||||
<ID>LongMethod:EditServerFragment.kt$EditServerFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
|
||||
<ID>LongMethod:FilePickerAdapter.kt$FilePickerAdapter$private fun fileLister(currentDirectory: File)</ID>
|
||||
|
@ -64,25 +43,11 @@
|
|||
<ID>LongMethod:TrackCollectionFragment.kt$TrackCollectionFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
|
||||
<ID>LongMethod:TrackCollectionFragment.kt$TrackCollectionFragment$private fun updateDisplay(refresh: Boolean)</ID>
|
||||
<ID>LongMethod:TrackCollectionFragment.kt$TrackCollectionFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)</ID>
|
||||
<ID>LongParameterList:DownloadHandler.kt$DownloadHandler$( fragment: Fragment, append: Boolean, save: Boolean, autoPlay: Boolean, playNext: Boolean, shuffle: Boolean, songs: List<MusicDirectory.Entry?> )</ID>
|
||||
<ID>LongParameterList:DownloadHandler.kt$DownloadHandler$( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID>
|
||||
<ID>LongParameterList:DownloadHandler.kt$DownloadHandler$( fragment: Fragment, id: String, name: String?, save: Boolean, append: Boolean, autoplay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean )</ID>
|
||||
<ID>LongParameterList:DownloadHandler.kt$DownloadHandler$( fragment: Fragment, id: String?, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID>
|
||||
<ID>LongParameterList:ServerRowAdapter.kt$ServerRowAdapter$( private var context: Context, private var data: Array<ServerSetting>, private val model: ServerSettingsModel, private val activeServerProvider: ActiveServerProvider, private val manageMode: Boolean, private val serverDeletedCallback: ((Int) -> Unit), private val serverEditRequestedCallback: ((Int) -> Unit) )</ID>
|
||||
<ID>MagicNumber:ActiveServerProvider.kt$ActiveServerProvider$8192</ID>
|
||||
<ID>MagicNumber:AudioFocusHandler.kt$AudioFocusHandler$0.1f</ID>
|
||||
<ID>MagicNumber:DownloadFile.kt$DownloadFile$100</ID>
|
||||
<ID>MagicNumber:DownloadFile.kt$DownloadFile.DownloadTask$10</ID>
|
||||
<ID>MagicNumber:DownloadFile.kt$DownloadFile.DownloadTask$1000L</ID>
|
||||
<ID>MagicNumber:DownloadFile.kt$DownloadFile.DownloadTask$60</ID>
|
||||
<ID>MagicNumber:DownloadHandler.kt$DownloadHandler$500</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$100</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$3</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$4</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$5</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$6</ID>
|
||||
<ID>MagicNumber:FileLoggerTree.kt$FileLoggerTree$7</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer$100</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer$1000</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.<no name provided>$1000</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.<no name provided>$60000</ID>
|
||||
|
@ -94,16 +59,12 @@
|
|||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.BufferTask$8L</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.CheckCompletionTask$5000L</ID>
|
||||
<ID>MagicNumber:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$50L</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$100</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$1000</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$256</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$3</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService$4</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService.Companion$19</ID>
|
||||
<ID>MagicNumber:MediaPlayerService.kt$MediaPlayerService.Companion$50L</ID>
|
||||
<ID>MagicNumber:RESTMusicService.kt$RESTMusicService$206</ID>
|
||||
<ID>MagicNumber:RESTMusicService.kt$RESTMusicService$5</ID>
|
||||
<ID>MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10</ID>
|
||||
<ID>MagicNumber:SongView.kt$SongView$3</ID>
|
||||
<ID>MagicNumber:SongView.kt$SongView$4</ID>
|
||||
<ID>MagicNumber:SongView.kt$SongView$60</ID>
|
||||
|
@ -120,17 +81,12 @@
|
|||
<ID>ReturnCount:ServerRowAdapter.kt$ServerRowAdapter$ private fun popupMenuItemClick(menuItem: MenuItem, position: Int): Boolean</ID>
|
||||
<ID>ReturnCount:TrackCollectionFragment.kt$TrackCollectionFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID>
|
||||
<ID>ReturnCount:TrackCollectionFragment.kt$TrackCollectionFragment$override fun onOptionsItemSelected(item: MenuItem): Boolean</ID>
|
||||
<ID>SpreadOperator:MediaPlayerService.kt$MediaPlayerService$(*compactActions)</ID>
|
||||
<ID>SwallowedException:DownloadFile.kt$DownloadFile$catch (e: Exception) { Timber.w("Failed to set last-modified date on %s", file) }</ID>
|
||||
<ID>SwallowedException:DownloadFile.kt$DownloadFile$catch (ex: IOException) { Timber.w("Failed to rename file %s to %s", completeFile, saveFile) }</ID>
|
||||
<ID>SwallowedException:LocalMediaPlayer.kt$LocalMediaPlayer$catch (e: Throwable) { // Froyo or lower }</ID>
|
||||
<ID>SwallowedException:LocalMediaPlayer.kt$LocalMediaPlayer$catch (e: Throwable) { }</ID>
|
||||
<ID>SwallowedException:MediaPlayerService.kt$MediaPlayerService$catch (x: IndexOutOfBoundsException) { // Ignored }</ID>
|
||||
<ID>SwallowedException:NavigationActivity.kt$NavigationActivity$catch (e: Resources.NotFoundException) { destination.id.toString() }</ID>
|
||||
<ID>ThrowsCount:ApiCallResponseChecker.kt$ApiCallResponseChecker.Companion$@Throws(SubsonicRESTException::class, IOException::class) fun checkResponseSuccessful(response: Response<out SubsonicResponse>)</ID>
|
||||
<ID>TooGenericExceptionCaught:ArtistListModel.kt$ArtistListModel$exception: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:DownloadFile.kt$DownloadFile$e: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:DownloadFile.kt$DownloadFile.DownloadTask$x: Exception</ID>
|
||||
<ID>TooGenericExceptionCaught:FileLoggerTree.kt$FileLoggerTree$x: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer$e: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer$ex: Exception</ID>
|
||||
|
@ -147,12 +103,8 @@
|
|||
<ID>TooManyFunctions:MediaPlayerService.kt$MediaPlayerService : Service</ID>
|
||||
<ID>TooManyFunctions:RESTMusicService.kt$RESTMusicService : MusicService</ID>
|
||||
<ID>TooManyFunctions:TrackCollectionFragment.kt$TrackCollectionFragment : Fragment</ID>
|
||||
<ID>TopLevelPropertyNaming:SubsonicUncaughtExceptionHandler.kt$private const val filename = "ultrasonic-stacktrace.txt"</ID>
|
||||
<ID>UnusedPrivateMember:RESTMusicService.kt$RESTMusicService.Companion$private const val INDEXES_FOLDER_STORAGE_NAME = "indexes_folder"</ID>
|
||||
<ID>UselessCallOnNotNull:FileLoggerTree.kt$FileLoggerTree$fileList.isNullOrEmpty()</ID>
|
||||
<ID>UselessCallOnNotNull:FileLoggerTree.kt$FileLoggerTree.Companion$fileList.isNullOrEmpty()</ID>
|
||||
<ID>UtilityClassWithPublicConstructor:CommunicationErrorHandler.kt$CommunicationErrorHandler</ID>
|
||||
<ID>UtilityClassWithPublicConstructor:FragmentTitle.kt$FragmentTitle</ID>
|
||||
<ID>VariableNaming:SelectMusicFolderView.kt$SelectMusicFolderView$private val MENU_GROUP_MUSIC_FOLDER = 10</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
|
@ -62,13 +62,15 @@ style:
|
|||
maxLineLength: 120
|
||||
excludePackageStatements: false
|
||||
excludeImportStatements: false
|
||||
MagicNumber:
|
||||
ignoreNumbers: ['-1', '0', '1', '2', '100']
|
||||
ignoreEnums: true
|
||||
ignorePropertyDeclaration: true
|
||||
UnnecessaryAbstractClass:
|
||||
active: false
|
||||
|
||||
comments:
|
||||
active: true
|
||||
CommentOverPrivateFunction:
|
||||
active: true
|
||||
CommentOverPrivateProperty:
|
||||
active: true
|
||||
UndocumentedPublicClass:
|
||||
active: false
|
||||
searchInNestedClass: true
|
||||
|
|
|
@ -8,6 +8,5 @@ kotlin.incremental=true
|
|||
kotlin.caching.enabled=true
|
||||
kotlin.incremental.usePreciseJavaTracking=true
|
||||
|
||||
android.enableBuildCache=true
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
|
|
@ -22,6 +22,9 @@ if (isCodeQualityEnabled) {
|
|||
detekt {
|
||||
buildUponDefaultConfig = true
|
||||
toolVersion = versions.detekt
|
||||
// Builds the AST in parallel. Rules are always executed in parallel.
|
||||
// Can lead to speedups in larger projects.
|
||||
parallel = true
|
||||
baseline = file("${rootProject.projectDir}/detekt-baseline.xml")
|
||||
config = files("${rootProject.projectDir}/detekt-config.yml")
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
include ':core:library'
|
||||
include ':core:domain'
|
||||
include ':core:subsonic-api'
|
||||
include ':core:subsonic-api-image-loader'
|
||||
|
|
|
@ -47,9 +47,11 @@ android {
|
|||
|
||||
lintOptions {
|
||||
baselineFile file("lint-baseline.xml")
|
||||
warning 'MissingTranslation'
|
||||
ignore 'MissingTranslation'
|
||||
warning 'ImpliedQuantity'
|
||||
disable 'IconMissingDensityFolder'
|
||||
abortOnError true
|
||||
warningsAsErrors true
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
|
@ -66,7 +68,6 @@ tasks.withType(Test) {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':core:library')
|
||||
implementation project(':core:domain')
|
||||
implementation project(':core:subsonic-api')
|
||||
implementation project(':core:subsonic-api-image-loader')
|
||||
|
@ -95,6 +96,7 @@ dependencies {
|
|||
implementation other.koinViewModel
|
||||
implementation other.okhttpLogging
|
||||
implementation other.fastScroll
|
||||
implementation other.sortListView
|
||||
|
||||
kapt androidSupport.room
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -20,7 +20,7 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
Par défaut, cette application n'est pas configurée</b>. Après avoir configuré votre
|
||||
Par défaut, cette application n'est pas configurée. Après avoir configuré votre
|
||||
serveur personnel, veuillez accéder aux <b>Paramètres</b> et modifier la configuration afin de vous connecter à votre propre ordinateur ou vos appareils mobiles.
|
||||
</p>
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.moire.ultrasonic.R;
|
|||
import org.moire.ultrasonic.util.Util;
|
||||
|
||||
/**
|
||||
* Displays online help and about information in a webWiew
|
||||
* Displays online help and about information in a WebView
|
||||
*/
|
||||
public class AboutFragment extends Fragment {
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
package org.moire.ultrasonic.service;
|
||||
|
||||
import org.moire.ultrasonic.audiofx.EqualizerController;
|
||||
import org.moire.ultrasonic.audiofx.VisualizerController;
|
||||
import org.moire.ultrasonic.domain.MusicDirectory.Entry;
|
||||
import org.moire.ultrasonic.domain.PlayerState;
|
||||
import org.moire.ultrasonic.domain.RepeatMode;
|
||||
|
|
|
@ -24,11 +24,6 @@ import kotlin.Lazy;
|
|||
|
||||
import static org.koin.java.KoinJavaComponent.inject;
|
||||
|
||||
/**
|
||||
* @author Sindre Mehus
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
/**
|
||||
* Responsible for cleaning up files from the offline download cache on the filesystem
|
||||
*/
|
||||
|
@ -207,17 +202,8 @@ public class CacheCleaner
|
|||
@Override
|
||||
public int compare(File a, File b)
|
||||
{
|
||||
if (a.lastModified() < b.lastModified())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return Long.compare(a.lastModified(), b.lastModified());
|
||||
|
||||
if (a.lastModified() > b.lastModified())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class EntryByDiscAndTrackComparator implements Comparator<MusicDirectory.
|
|||
|
||||
private static int compare(long a, long b)
|
||||
{
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
return Long.compare(a, b);
|
||||
}
|
||||
|
||||
private static int compare(String a, String b)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/***
|
||||
/**
|
||||
Copyright (c) 2008-2009 CommonsWare, LLC
|
||||
Portions (c) 2009 Google, Inc.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/***
|
||||
/**
|
||||
Copyright (c) 2008-2009 CommonsWare, LLC
|
||||
Portions (c) 2009 Google, Inc.
|
||||
|
||||
|
|
|
@ -68,8 +68,8 @@ public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexe
|
|||
}
|
||||
}
|
||||
|
||||
sections = sectionSet.toArray(new Object[sectionSet.size()]);
|
||||
positions = positionList.toArray(new Integer[positionList.size()]);
|
||||
sections = sectionSet.toArray(new Object[0]);
|
||||
positions = positionList.toArray(new Integer[0]);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.content.Context;
|
|||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
|
||||
|
|
|
@ -66,8 +66,8 @@ public class GenreAdapter extends ArrayAdapter<Genre> implements SectionIndexer
|
|||
}
|
||||
}
|
||||
|
||||
sections = sectionSet.toArray(new Object[sectionSet.size()]);
|
||||
positions = positionList.toArray(new Integer[positionList.size()]);
|
||||
sections = sectionSet.toArray(new Object[0]);
|
||||
positions = positionList.toArray(new Integer[0]);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
|
@ -32,7 +32,7 @@ public class PodcastsChannelsAdapter extends ArrayAdapter<PodcastsChannel> {
|
|||
PodcastsChannel entry = getItem(position);
|
||||
|
||||
TextView view;
|
||||
if (convertView != null && convertView instanceof PlaylistView) {
|
||||
if (convertView instanceof PlaylistView) {
|
||||
view = (TextView) convertView;
|
||||
} else {
|
||||
view = (TextView) layoutInflater
|
||||
|
|
|
@ -28,7 +28,7 @@ public class SongListAdapter extends ArrayAdapter<DownloadFile>
|
|||
|
||||
SongView view;
|
||||
|
||||
if (convertView != null && convertView instanceof SongView)
|
||||
if (convertView instanceof SongView)
|
||||
{
|
||||
SongView currentView = (SongView) convertView;
|
||||
if (currentView.getEntry().equals(entry))
|
||||
|
|
|
@ -13,6 +13,7 @@ import timber.log.Timber
|
|||
* A Timber Tree which can be used to log to a file
|
||||
* Subclass of the DebugTree so it inherits the Tag handling
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
class FileLoggerTree : Timber.DebugTree() {
|
||||
private val dateFormat = SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault())
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.io.IOException
|
|||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.io.RandomAccessFile
|
||||
import org.koin.core.component.KoinApiExtension
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
import org.moire.ultrasonic.domain.MusicDirectory
|
||||
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
|
||||
|
@ -34,6 +35,7 @@ import timber.log.Timber
|
|||
* @author Sindre Mehus
|
||||
* @version $Id$
|
||||
*/
|
||||
@KoinApiExtension
|
||||
class DownloadFile(
|
||||
private val context: Context,
|
||||
val song: MusicDirectory.Entry,
|
||||
|
@ -190,8 +192,8 @@ class DownloadFile(
|
|||
}
|
||||
completeWhenDone = false
|
||||
}
|
||||
} catch (ex: IOException) {
|
||||
Timber.w("Failed to rename file %s to %s", completeFile, saveFile)
|
||||
} catch (e: IOException) {
|
||||
Timber.w(e, "Failed to rename file %s to %s", completeFile, saveFile)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,6 +201,8 @@ class DownloadFile(
|
|||
return String.format("DownloadFile (%s)", song)
|
||||
}
|
||||
|
||||
@KoinApiExtension
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
private inner class DownloadTask : CancellableTask() {
|
||||
override fun execute() {
|
||||
var inputStream: InputStream? = null
|
||||
|
@ -286,7 +290,7 @@ class DownloadFile(
|
|||
Util.renameFile(partialFile, completeFile)
|
||||
}
|
||||
}
|
||||
} catch (x: Exception) {
|
||||
} catch (e: Exception) {
|
||||
Util.close(outputStream)
|
||||
Util.delete(completeFile)
|
||||
Util.delete(saveFile)
|
||||
|
@ -295,7 +299,7 @@ class DownloadFile(
|
|||
if (retryCount > 0) {
|
||||
--retryCount
|
||||
}
|
||||
Timber.w(x, "Failed to download '%s'.", song)
|
||||
Timber.w(e, "Failed to download '%s'.", song)
|
||||
}
|
||||
} finally {
|
||||
Util.close(inputStream)
|
||||
|
@ -332,8 +336,8 @@ class DownloadFile(
|
|||
val size = Util.getMinDisplayMetric(context)
|
||||
musicService.getCoverArt(song, size, true, true)
|
||||
}
|
||||
} catch (x: Exception) {
|
||||
Timber.e(x, "Failed to get cover art.")
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Failed to get cover art.")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,7 +380,7 @@ class DownloadFile(
|
|||
raf.setLength(length)
|
||||
raf.close()
|
||||
} catch (e: Exception) {
|
||||
Timber.w("Failed to set last-modified date on %s", file)
|
||||
Timber.w(e, "Failed to set last-modified date on %s", file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import timber.log.Timber
|
|||
* Android Foreground Service for playing music
|
||||
* while the rest of the Ultrasonic App is in the background.
|
||||
*/
|
||||
@Suppress("LargeClass")
|
||||
class MediaPlayerService : Service() {
|
||||
private val binder: IBinder = SimpleServiceBinder(this)
|
||||
private val scrobbler = Scrobbler()
|
||||
|
@ -596,6 +597,7 @@ class MediaPlayerService : Service() {
|
|||
/**
|
||||
* This method builds a notification, reusing the Notification Builder if possible
|
||||
*/
|
||||
@Suppress("SpreadOperator")
|
||||
private fun buildForegroundNotification(
|
||||
playerState: PlayerState,
|
||||
currentPlaying: DownloadFile?
|
||||
|
@ -893,6 +895,7 @@ class MediaPlayerService : Service() {
|
|||
mediaSession?.setMediaButtonReceiver(null)
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
companion object {
|
||||
private const val NOTIFICATION_CHANNEL_ID = "org.moire.ultrasonic"
|
||||
private const val NOTIFICATION_CHANNEL_NAME = "Ultrasonic background service"
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.moire.ultrasonic.util.Util
|
|||
/**
|
||||
* Retrieves a list of songs and adds them to the now playing list
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
@KoinApiExtension
|
||||
class DownloadHandler(
|
||||
val mediaPlayerController: MediaPlayerController,
|
||||
|
|
|
@ -6,8 +6,6 @@ import java.io.File
|
|||
import java.io.PrintWriter
|
||||
import timber.log.Timber
|
||||
|
||||
private const val filename = "ultrasonic-stacktrace.txt"
|
||||
|
||||
/**
|
||||
* Logs the stack trace of uncaught exceptions to a file on the SD card.
|
||||
*/
|
||||
|
@ -22,7 +20,7 @@ class SubsonicUncaughtExceptionHandler(
|
|||
var printWriter: PrintWriter? = null
|
||||
|
||||
try {
|
||||
file = File(FileUtil.getUltrasonicDirectory(), filename)
|
||||
file = File(FileUtil.getUltrasonicDirectory(), STACKTRACE_NAME)
|
||||
printWriter = PrintWriter(file)
|
||||
val logMessage = String.format(
|
||||
"Android API level: %s\nUltrasonic version name: %s\n" +
|
||||
|
@ -40,4 +38,8 @@ class SubsonicUncaughtExceptionHandler(
|
|||
defaultHandler?.uncaughtException(thread, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STACKTRACE_NAME = "ultrasonic-stacktrace.txt"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue