@ -0,0 +1,8 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<classpath> |
||||||
|
<classpathentry kind="src" path="src"/> |
||||||
|
<classpathentry kind="src" path="gen"/> |
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> |
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> |
||||||
|
<classpathentry kind="output" path="bin/classes"/> |
||||||
|
</classpath> |
@ -0,0 +1,2 @@ |
|||||||
|
# Auto detect text files and perform LF normalization |
||||||
|
* text=auto |
@ -0,0 +1,4 @@ |
|||||||
|
/bin |
||||||
|
/gen |
||||||
|
.classpath |
||||||
|
.project |
@ -0,0 +1,33 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<projectDescription> |
||||||
|
<name>ColorPickerPreference</name> |
||||||
|
<comment></comment> |
||||||
|
<projects> |
||||||
|
</projects> |
||||||
|
<buildSpec> |
||||||
|
<buildCommand> |
||||||
|
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
<buildCommand> |
||||||
|
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
<buildCommand> |
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
<buildCommand> |
||||||
|
<name>com.android.ide.eclipse.adt.ApkBuilder</name> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
</buildSpec> |
||||||
|
<natures> |
||||||
|
<nature>com.android.ide.eclipse.adt.AndroidNature</nature> |
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature> |
||||||
|
</natures> |
||||||
|
</projectDescription> |
@ -0,0 +1,18 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
package="net.margaritov.preference.colorpicker" |
||||||
|
android:versionCode="0111" |
||||||
|
android:versionName="1.11"> |
||||||
|
<application android:icon="@drawable/icon" android:label="@string/app_name"> |
||||||
|
<activity android:name="net.margaritov.preference.colorpicker.Test" |
||||||
|
android:label="@string/app_name"> |
||||||
|
<intent-filter> |
||||||
|
<action android:name="android.intent.action.MAIN" /> |
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
</activity> |
||||||
|
|
||||||
|
</application> |
||||||
|
<uses-sdk android:minSdkVersion="7" /> |
||||||
|
|
||||||
|
</manifest> |
@ -0,0 +1,26 @@ |
|||||||
|
================================ |
||||||
|
ColorPickerPreference Change Log |
||||||
|
================================ |
||||||
|
|
||||||
|
2011-02-11 v1.11: |
||||||
|
---------------- |
||||||
|
fix: color controls not visible in landscape orientation |
||||||
|
fix: colorPickerDialog constructor was protected |
||||||
|
|
||||||
|
2011-01-25 v1.1: |
||||||
|
---------------- |
||||||
|
* new: Alpha Slider is disabled by default |
||||||
|
* new: Alpha Slider can be enabled: |
||||||
|
* with preference XML using attribute alphaSlider="true" |
||||||
|
* with function setAlphaSliderEnabled(true) |
||||||
|
* new: defaultValue in preference XML now accepts HEX color code: |
||||||
|
* #FF00FF, rgb |
||||||
|
* #FF00FF00, argb |
||||||
|
|
||||||
|
2011-01-20 v1.01: |
||||||
|
----------------- |
||||||
|
fix: sometimes preview color disappear |
||||||
|
|
||||||
|
2011-01-19 v1.0: |
||||||
|
---------------- |
||||||
|
release |
@ -0,0 +1,15 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2011 Sergey Margaritov & Daniel Nilsson |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
@ -0,0 +1,47 @@ |
|||||||
|
===================== |
||||||
|
ColorPickerPreference |
||||||
|
===================== |
||||||
|
|
||||||
|
Generally used classes by Daniel Nilsson. |
||||||
|
ColorPickerPreference class by Sergey Margaritov. |
||||||
|
Packed by Sergey Margaritov. |
||||||
|
|
||||||
|
Features |
||||||
|
======== |
||||||
|
|
||||||
|
* Color Area |
||||||
|
* Hue Slider |
||||||
|
* Alpha Slider (disabled by default) |
||||||
|
* Old & New Color |
||||||
|
* Color Preview in Preferences List |
||||||
|
|
||||||
|
Requirements |
||||||
|
============ |
||||||
|
|
||||||
|
Tested with APIv7, but maybe will work with early versions |
||||||
|
|
||||||
|
Usage |
||||||
|
===== |
||||||
|
|
||||||
|
You can see some tests inside |
||||||
|
|
||||||
|
:: |
||||||
|
|
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPreference |
||||||
|
android:key="color1" |
||||||
|
android:title="@string/color1_title" |
||||||
|
android:summary="@string/color1_summary" |
||||||
|
android:defaultValue="@color/pumpkin_orange" <!-- integer resources are also accepted --> |
||||||
|
alphaSlider="true" <!-- enable alpha slider via XML --> |
||||||
|
/> |
||||||
|
|
||||||
|
To enable Alpha Slider in your code use function: |
||||||
|
:: |
||||||
|
setAlphaSliderEnabled(boolean enable) |
||||||
|
|
||||||
|
Screens |
||||||
|
======= |
||||||
|
|
||||||
|
* .. image:: https://github.com/attenzione/android-ColorPickerPreference/raw/master/screen_1.png |
||||||
|
|
||||||
|
* .. image:: https://github.com/attenzione/android-ColorPickerPreference/raw/master/screen_2.png |
@ -0,0 +1,34 @@ |
|||||||
|
-optimizationpasses 5 |
||||||
|
-dontusemixedcaseclassnames |
||||||
|
-dontskipnonpubliclibraryclasses |
||||||
|
-dontpreverify |
||||||
|
-verbose |
||||||
|
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* |
||||||
|
|
||||||
|
-keep public class * extends android.app.Activity |
||||||
|
-keep public class * extends android.app.Application |
||||||
|
-keep public class * extends android.app.Service |
||||||
|
-keep public class * extends android.content.BroadcastReceiver |
||||||
|
-keep public class * extends android.content.ContentProvider |
||||||
|
-keep public class com.android.vending.licensing.ILicensingService |
||||||
|
|
||||||
|
-keepclasseswithmembernames class * { |
||||||
|
native <methods>; |
||||||
|
} |
||||||
|
|
||||||
|
-keepclasseswithmembernames class * { |
||||||
|
public <init>(android.content.Context, android.util.AttributeSet); |
||||||
|
} |
||||||
|
|
||||||
|
-keepclasseswithmembernames class * { |
||||||
|
public <init>(android.content.Context, android.util.AttributeSet, int); |
||||||
|
} |
||||||
|
|
||||||
|
-keepclassmembers enum * { |
||||||
|
public static **[] values(); |
||||||
|
public static ** valueOf(java.lang.String); |
||||||
|
} |
||||||
|
|
||||||
|
-keep class * implements android.os.Parcelable { |
||||||
|
public static final android.os.Parcelable$Creator *; |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
# This file is automatically generated by Android Tools. |
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED! |
||||||
|
# |
||||||
|
# This file must be checked in Version Control Systems. |
||||||
|
# |
||||||
|
# To customize properties used by the Ant build system use, |
||||||
|
# "ant.properties", and override values to adapt the script to your |
||||||
|
# project structure. |
||||||
|
|
||||||
|
android.library=true |
||||||
|
# Project target. |
||||||
|
target=android-16 |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.5 KiB |
@ -0,0 +1,77 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<!-- Copyright (C) 2010 Daniel Nilsson |
||||||
|
|
||||||
|
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. |
||||||
|
--> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:paddingLeft="5dp" |
||||||
|
android:paddingRight="5dp" |
||||||
|
android:orientation="horizontal"> |
||||||
|
|
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerView |
||||||
|
android:id="@+id/color_picker_view" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:tag="landscape" |
||||||
|
android:layerType="software" |
||||||
|
/> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:orientation="vertical" |
||||||
|
android:layout_marginBottom="10dp"> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:text="@string/press_color_to_apply" |
||||||
|
android:gravity="center" |
||||||
|
android:layout_marginTop="6dp" |
||||||
|
android:layout_marginLeft="6dp" |
||||||
|
android:layout_marginRight="6dp" |
||||||
|
android:layout_marginBottom="5dp" |
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall" |
||||||
|
/> |
||||||
|
|
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPanelView |
||||||
|
android:id="@+id/old_color_panel" |
||||||
|
android:layout_width="fill_parent" |
||||||
|
android:layout_height="40dp" |
||||||
|
android:layout_weight="0.5" |
||||||
|
/> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:layout_width="fill_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:text="↓" |
||||||
|
android:textSize="20sp" |
||||||
|
android:gravity="center" |
||||||
|
android:layout_marginTop="10dp" |
||||||
|
android:layout_marginBottom="10dp" |
||||||
|
/> |
||||||
|
|
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPanelView |
||||||
|
android:id="@+id/new_color_panel" |
||||||
|
android:layout_width="fill_parent" |
||||||
|
android:layout_height="40dp" |
||||||
|
android:layout_weight="0.5" |
||||||
|
/> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
</LinearLayout> |
@ -0,0 +1,78 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<!-- Copyright (C) 2010 Daniel Nilsson |
||||||
|
|
||||||
|
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. |
||||||
|
--> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:paddingLeft="5dp" |
||||||
|
android:paddingRight="5dp" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerView |
||||||
|
android:id="@+id/color_picker_view" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_centerHorizontal="true" |
||||||
|
android:tag="portrait" |
||||||
|
android:layerType="software" |
||||||
|
/> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:text="@string/press_color_to_apply" |
||||||
|
android:gravity="left" |
||||||
|
android:layout_marginLeft="6dp" |
||||||
|
android:layout_marginRight="6dp" |
||||||
|
android:layout_marginBottom="5dp" |
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall" |
||||||
|
/> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="40dp" |
||||||
|
android:orientation="horizontal" |
||||||
|
android:layout_below="@id/color_picker_view" |
||||||
|
android:layout_marginBottom="10dp"> |
||||||
|
|
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPanelView |
||||||
|
android:id="@+id/old_color_panel" |
||||||
|
android:layout_width="0px" |
||||||
|
android:layout_height="fill_parent" |
||||||
|
android:layout_weight="0.5" |
||||||
|
/> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="fill_parent" |
||||||
|
android:text="→" |
||||||
|
android:textSize="20sp" |
||||||
|
android:gravity="center" |
||||||
|
android:layout_marginLeft="10dp" |
||||||
|
android:layout_marginRight="10dp" |
||||||
|
/> |
||||||
|
|
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPanelView |
||||||
|
android:id="@+id/new_color_panel" |
||||||
|
android:layout_width="0px" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_weight="0.5" |
||||||
|
/> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
</LinearLayout> |
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<resources> |
||||||
|
<integer name="COLOR_BLACK">0xff000000</integer> |
||||||
|
<integer name="COLOR_GREEN">0xff00ff00</integer> |
||||||
|
</resources> |
@ -0,0 +1,21 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<!-- App --> |
||||||
|
<string name="hello">Hello World, Main!</string> |
||||||
|
<string name="app_name">ColorPickerPreference</string> |
||||||
|
|
||||||
|
<!-- Color Picker --> |
||||||
|
<string name="dialog_color_picker">Color Picker</string> |
||||||
|
<string name="press_color_to_apply">Press on Color to apply</string> |
||||||
|
|
||||||
|
<!-- Preferences --> |
||||||
|
<string name="pref_category">Category</string> |
||||||
|
<string name="color1_title">Color 1</string> |
||||||
|
<string name="color1_summary">black color by default, set by reference</string> |
||||||
|
<string name="color2_title">Color 2</string> |
||||||
|
<string name="color2_summary">not persistent color\nalpha slider added via code</string> |
||||||
|
<string name="color3_title">Color 3</string> |
||||||
|
<string name="color3_summary">picker with alpha slider</string> |
||||||
|
<string name="color4_title">Color 4</string> |
||||||
|
<string name="color4_summary">color set with HEX code in xml</string> |
||||||
|
</resources> |
@ -0,0 +1,32 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<PreferenceCategory android:title="@string/pref_category"> |
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPreference |
||||||
|
android:key="color1" |
||||||
|
android:title="@string/color1_title" |
||||||
|
android:summary="@string/color1_summary" |
||||||
|
android:defaultValue="@integer/COLOR_BLACK" |
||||||
|
/> |
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPreference |
||||||
|
android:key="color2" |
||||||
|
android:persistent="false" |
||||||
|
android:title="@string/color2_title" |
||||||
|
android:summary="@string/color2_summary" |
||||||
|
android:defaultValue="@integer/COLOR_GREEN" |
||||||
|
/> |
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPreference |
||||||
|
android:key="color3" |
||||||
|
android:title="@string/color3_title" |
||||||
|
android:summary="@string/color3_summary" |
||||||
|
android:defaultValue="@integer/COLOR_GREEN" |
||||||
|
alphaSlider="true" |
||||||
|
/> |
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPreference |
||||||
|
android:key="color4" |
||||||
|
android:persistent="false" |
||||||
|
android:title="@string/color4_title" |
||||||
|
android:summary="@string/color4_summary" |
||||||
|
android:defaultValue="#0000FF" |
||||||
|
/> |
||||||
|
</PreferenceCategory> |
||||||
|
</PreferenceScreen> |
After Width: | Height: | Size: 122 KiB |
After Width: | Height: | Size: 67 KiB |
@ -0,0 +1,128 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2010 Daniel Nilsson |
||||||
|
* |
||||||
|
* 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 net.margaritov.preference.colorpicker; |
||||||
|
|
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.Bitmap.Config; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.ColorFilter; |
||||||
|
import android.graphics.Paint; |
||||||
|
import android.graphics.Rect; |
||||||
|
import android.graphics.drawable.Drawable; |
||||||
|
|
||||||
|
/** |
||||||
|
* This drawable that draws a simple white and gray chessboard pattern. |
||||||
|
* It's pattern you will often see as a background behind a |
||||||
|
* partly transparent image in many applications. |
||||||
|
* @author Daniel Nilsson |
||||||
|
*/ |
||||||
|
public class AlphaPatternDrawable extends Drawable { |
||||||
|
|
||||||
|
private int mRectangleSize = 10; |
||||||
|
|
||||||
|
private Paint mPaint = new Paint(); |
||||||
|
private Paint mPaintWhite = new Paint(); |
||||||
|
private Paint mPaintGray = new Paint(); |
||||||
|
|
||||||
|
private int numRectanglesHorizontal; |
||||||
|
private int numRectanglesVertical; |
||||||
|
|
||||||
|
/** |
||||||
|
* Bitmap in which the pattern will be cahched. |
||||||
|
*/ |
||||||
|
private Bitmap mBitmap; |
||||||
|
|
||||||
|
public AlphaPatternDrawable(int rectangleSize) { |
||||||
|
mRectangleSize = rectangleSize; |
||||||
|
mPaintWhite.setColor(0xffffffff); |
||||||
|
mPaintGray.setColor(0xffcbcbcb); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void draw(Canvas canvas) { |
||||||
|
canvas.drawBitmap(mBitmap, null, getBounds(), mPaint); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getOpacity() { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setAlpha(int alpha) { |
||||||
|
throw new UnsupportedOperationException("Alpha is not supported by this drawwable."); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setColorFilter(ColorFilter cf) { |
||||||
|
throw new UnsupportedOperationException("ColorFilter is not supported by this drawwable."); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onBoundsChange(Rect bounds) { |
||||||
|
super.onBoundsChange(bounds); |
||||||
|
|
||||||
|
int height = bounds.height(); |
||||||
|
int width = bounds.width(); |
||||||
|
|
||||||
|
numRectanglesHorizontal = (int) Math.ceil((width / mRectangleSize)); |
||||||
|
numRectanglesVertical = (int) Math.ceil(height / mRectangleSize); |
||||||
|
|
||||||
|
generatePatternBitmap(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This will generate a bitmap with the pattern |
||||||
|
* as big as the rectangle we were allow to draw on. |
||||||
|
* We do this to chache the bitmap so we don't need to |
||||||
|
* recreate it each time draw() is called since it |
||||||
|
* takes a few milliseconds. |
||||||
|
*/ |
||||||
|
private void generatePatternBitmap(){ |
||||||
|
|
||||||
|
if(getBounds().width() <= 0 || getBounds().height() <= 0){ |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
mBitmap = Bitmap.createBitmap(getBounds().width(), getBounds().height(), Config.ARGB_8888); |
||||||
|
Canvas canvas = new Canvas(mBitmap); |
||||||
|
|
||||||
|
Rect r = new Rect(); |
||||||
|
boolean verticalStartWhite = true; |
||||||
|
for (int i = 0; i <= numRectanglesVertical; i++) { |
||||||
|
|
||||||
|
boolean isWhite = verticalStartWhite; |
||||||
|
for (int j = 0; j <= numRectanglesHorizontal; j++) { |
||||||
|
|
||||||
|
r.top = i * mRectangleSize; |
||||||
|
r.left = j * mRectangleSize; |
||||||
|
r.bottom = r.top + mRectangleSize; |
||||||
|
r.right = r.left + mRectangleSize; |
||||||
|
|
||||||
|
canvas.drawRect(r, isWhite ? mPaintWhite : mPaintGray); |
||||||
|
|
||||||
|
isWhite = !isWhite; |
||||||
|
} |
||||||
|
|
||||||
|
verticalStartWhite = !verticalStartWhite; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,142 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2010 Daniel Nilsson |
||||||
|
* |
||||||
|
* 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 net.margaritov.preference.colorpicker; |
||||||
|
|
||||||
|
import android.app.Dialog; |
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.PixelFormat; |
||||||
|
import android.os.Bundle; |
||||||
|
import android.view.LayoutInflater; |
||||||
|
import android.view.View; |
||||||
|
import android.widget.LinearLayout; |
||||||
|
|
||||||
|
public class ColorPickerDialog |
||||||
|
extends |
||||||
|
Dialog |
||||||
|
implements |
||||||
|
ColorPickerView.OnColorChangedListener, |
||||||
|
View.OnClickListener { |
||||||
|
|
||||||
|
private ColorPickerView mColorPicker; |
||||||
|
|
||||||
|
private ColorPickerPanelView mOldColor; |
||||||
|
private ColorPickerPanelView mNewColor; |
||||||
|
|
||||||
|
private OnColorChangedListener mListener; |
||||||
|
|
||||||
|
public interface OnColorChangedListener { |
||||||
|
public void onColorChanged(int color); |
||||||
|
} |
||||||
|
|
||||||
|
public ColorPickerDialog(Context context, int initialColor) { |
||||||
|
super(context); |
||||||
|
|
||||||
|
init(initialColor); |
||||||
|
} |
||||||
|
|
||||||
|
private void init(int color) { |
||||||
|
// To fight color banding.
|
||||||
|
getWindow().setFormat(PixelFormat.RGBA_8888); |
||||||
|
|
||||||
|
setUp(color); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void setUp(int color) { |
||||||
|
|
||||||
|
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
||||||
|
|
||||||
|
View layout = inflater.inflate(R.layout.dialog_color_picker, null); |
||||||
|
|
||||||
|
setContentView(layout); |
||||||
|
|
||||||
|
setTitle(R.string.dialog_color_picker); |
||||||
|
|
||||||
|
mColorPicker = (ColorPickerView) layout.findViewById(R.id.color_picker_view); |
||||||
|
mOldColor = (ColorPickerPanelView) layout.findViewById(R.id.old_color_panel); |
||||||
|
mNewColor = (ColorPickerPanelView) layout.findViewById(R.id.new_color_panel); |
||||||
|
|
||||||
|
((LinearLayout) mOldColor.getParent()).setPadding( |
||||||
|
Math.round(mColorPicker.getDrawingOffset()), |
||||||
|
0, |
||||||
|
Math.round(mColorPicker.getDrawingOffset()), |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
mOldColor.setOnClickListener(this); |
||||||
|
mNewColor.setOnClickListener(this); |
||||||
|
mColorPicker.setOnColorChangedListener(this); |
||||||
|
mOldColor.setColor(color); |
||||||
|
mColorPicker.setColor(color, true); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onColorChanged(int color) { |
||||||
|
|
||||||
|
mNewColor.setColor(color); |
||||||
|
|
||||||
|
/* |
||||||
|
if (mListener != null) { |
||||||
|
mListener.onColorChanged(color); |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void setAlphaSliderVisible(boolean visible) { |
||||||
|
mColorPicker.setAlphaSliderVisible(visible); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set a OnColorChangedListener to get notified when the color |
||||||
|
* selected by the user has changed. |
||||||
|
* @param listener |
||||||
|
*/ |
||||||
|
public void setOnColorChangedListener(OnColorChangedListener listener){ |
||||||
|
mListener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
public int getColor() { |
||||||
|
return mColorPicker.getColor(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onClick(View v) { |
||||||
|
if (v.getId() == R.id.new_color_panel) { |
||||||
|
if (mListener != null) { |
||||||
|
mListener.onColorChanged(mNewColor.getColor()); |
||||||
|
} |
||||||
|
} |
||||||
|
dismiss(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Bundle onSaveInstanceState() { |
||||||
|
Bundle state = super.onSaveInstanceState(); |
||||||
|
state.putInt("old_color", mOldColor.getColor()); |
||||||
|
state.putInt("new_color", mNewColor.getColor()); |
||||||
|
return state; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onRestoreInstanceState(Bundle savedInstanceState) { |
||||||
|
super.onRestoreInstanceState(savedInstanceState); |
||||||
|
mOldColor.setColor(savedInstanceState.getInt("old_color")); |
||||||
|
mColorPicker.setColor(savedInstanceState.getInt("new_color"), true); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,171 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2010 Daniel Nilsson |
||||||
|
* |
||||||
|
* 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 net.margaritov.preference.colorpicker; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Paint; |
||||||
|
import android.graphics.RectF; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class draws a panel which which will be filled with a color which can be set. |
||||||
|
* It can be used to show the currently selected color which you will get from |
||||||
|
* the {@link ColorPickerView}. |
||||||
|
* @author Daniel Nilsson |
||||||
|
* |
||||||
|
*/ |
||||||
|
public class ColorPickerPanelView extends View { |
||||||
|
|
||||||
|
/** |
||||||
|
* The width in pixels of the border |
||||||
|
* surrounding the color panel. |
||||||
|
*/ |
||||||
|
private final static float BORDER_WIDTH_PX = 1; |
||||||
|
|
||||||
|
private float mDensity = 1f; |
||||||
|
|
||||||
|
private int mBorderColor = 0xff6E6E6E; |
||||||
|
private int mColor = 0xff000000; |
||||||
|
|
||||||
|
private Paint mBorderPaint; |
||||||
|
private Paint mColorPaint; |
||||||
|
|
||||||
|
private RectF mDrawingRect; |
||||||
|
private RectF mColorRect; |
||||||
|
|
||||||
|
private AlphaPatternDrawable mAlphaPattern; |
||||||
|
|
||||||
|
|
||||||
|
public ColorPickerPanelView(Context context){ |
||||||
|
this(context, null); |
||||||
|
} |
||||||
|
|
||||||
|
public ColorPickerPanelView(Context context, AttributeSet attrs){ |
||||||
|
this(context, attrs, 0); |
||||||
|
} |
||||||
|
|
||||||
|
public ColorPickerPanelView(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
private void init(){ |
||||||
|
mBorderPaint = new Paint(); |
||||||
|
mColorPaint = new Paint(); |
||||||
|
mDensity = getContext().getResources().getDisplayMetrics().density; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onDraw(Canvas canvas) { |
||||||
|
|
||||||
|
final RectF rect = mColorRect; |
||||||
|
|
||||||
|
if(BORDER_WIDTH_PX > 0){ |
||||||
|
mBorderPaint.setColor(mBorderColor); |
||||||
|
canvas.drawRect(mDrawingRect, mBorderPaint); |
||||||
|
} |
||||||
|
|
||||||
|
if(mAlphaPattern != null){ |
||||||
|
mAlphaPattern.draw(canvas); |
||||||
|
} |
||||||
|
|
||||||
|
mColorPaint.setColor(mColor); |
||||||
|
|
||||||
|
canvas.drawRect(rect, mColorPaint); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
||||||
|
|
||||||
|
int width = MeasureSpec.getSize(widthMeasureSpec); |
||||||
|
int height = MeasureSpec.getSize(heightMeasureSpec); |
||||||
|
|
||||||
|
setMeasuredDimension(width, height); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
||||||
|
super.onSizeChanged(w, h, oldw, oldh); |
||||||
|
|
||||||
|
mDrawingRect = new RectF(); |
||||||
|
mDrawingRect.left = getPaddingLeft(); |
||||||
|
mDrawingRect.right = w - getPaddingRight(); |
||||||
|
mDrawingRect.top = getPaddingTop(); |
||||||
|
mDrawingRect.bottom = h - getPaddingBottom(); |
||||||
|
|
||||||
|
setUpColorRect(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void setUpColorRect(){ |
||||||
|
final RectF dRect = mDrawingRect; |
||||||
|
|
||||||
|
float left = dRect.left + BORDER_WIDTH_PX; |
||||||
|
float top = dRect.top + BORDER_WIDTH_PX; |
||||||
|
float bottom = dRect.bottom - BORDER_WIDTH_PX; |
||||||
|
float right = dRect.right - BORDER_WIDTH_PX; |
||||||
|
|
||||||
|
mColorRect = new RectF(left,top, right, bottom); |
||||||
|
|
||||||
|
mAlphaPattern = new AlphaPatternDrawable((int)(5 * mDensity)); |
||||||
|
|
||||||
|
mAlphaPattern.setBounds( |
||||||
|
Math.round(mColorRect.left), |
||||||
|
Math.round(mColorRect.top), |
||||||
|
Math.round(mColorRect.right), |
||||||
|
Math.round(mColorRect.bottom) |
||||||
|
); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the color that should be shown by this view. |
||||||
|
* @param color |
||||||
|
*/ |
||||||
|
public void setColor(int color){ |
||||||
|
mColor = color; |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the color currently show by this view. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public int getColor(){ |
||||||
|
return mColor; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the color of the border surrounding the panel. |
||||||
|
* @param color |
||||||
|
*/ |
||||||
|
public void setBorderColor(int color){ |
||||||
|
mBorderColor = color; |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the color of the border surrounding the panel. |
||||||
|
*/ |
||||||
|
public int getBorderColor(){ |
||||||
|
return mBorderColor; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,287 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2011 Sergey Margaritov |
||||||
|
* |
||||||
|
* 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 net.margaritov.preference.colorpicker; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.res.TypedArray; |
||||||
|
import android.graphics.Bitmap; |
||||||
|
import android.graphics.Bitmap.Config; |
||||||
|
import android.graphics.Color; |
||||||
|
import android.os.Bundle; |
||||||
|
import android.os.Parcel; |
||||||
|
import android.os.Parcelable; |
||||||
|
import android.preference.Preference; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.View; |
||||||
|
import android.widget.ImageView; |
||||||
|
import android.widget.LinearLayout; |
||||||
|
|
||||||
|
/** |
||||||
|
* A preference type that allows a user to choose a time |
||||||
|
* @author Sergey Margaritov |
||||||
|
*/ |
||||||
|
public class ColorPickerPreference |
||||||
|
extends |
||||||
|
Preference |
||||||
|
implements |
||||||
|
Preference.OnPreferenceClickListener, |
||||||
|
ColorPickerDialog.OnColorChangedListener { |
||||||
|
|
||||||
|
View mView; |
||||||
|
ColorPickerDialog mDialog; |
||||||
|
private int mValue = Color.BLACK; |
||||||
|
private float mDensity = 0; |
||||||
|
private boolean mAlphaSliderEnabled = false; |
||||||
|
|
||||||
|
public ColorPickerPreference(Context context) { |
||||||
|
super(context); |
||||||
|
init(context, null); |
||||||
|
} |
||||||
|
|
||||||
|
public ColorPickerPreference(Context context, AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
init(context, attrs); |
||||||
|
} |
||||||
|
|
||||||
|
public ColorPickerPreference(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
init(context, attrs); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Object onGetDefaultValue(TypedArray a, int index) { |
||||||
|
return a.getColor(index, Color.BLACK); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { |
||||||
|
onColorChanged(restoreValue ? getPersistedInt(mValue) : (Integer) defaultValue); |
||||||
|
} |
||||||
|
|
||||||
|
private void init(Context context, AttributeSet attrs) { |
||||||
|
mDensity = getContext().getResources().getDisplayMetrics().density; |
||||||
|
setOnPreferenceClickListener(this); |
||||||
|
if (attrs != null) { |
||||||
|
mAlphaSliderEnabled = attrs.getAttributeBooleanValue(null, "alphaSlider", false); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onBindView(View view) { |
||||||
|
super.onBindView(view); |
||||||
|
mView = view; |
||||||
|
setPreviewColor(); |
||||||
|
} |
||||||
|
|
||||||
|
private void setPreviewColor() { |
||||||
|
if (mView == null) return; |
||||||
|
ImageView iView = new ImageView(getContext()); |
||||||
|
LinearLayout widgetFrameView = ((LinearLayout)mView.findViewById(android.R.id.widget_frame)); |
||||||
|
if (widgetFrameView == null) return; |
||||||
|
widgetFrameView.setVisibility(View.VISIBLE); |
||||||
|
widgetFrameView.setPadding( |
||||||
|
widgetFrameView.getPaddingLeft(), |
||||||
|
widgetFrameView.getPaddingTop(), |
||||||
|
(int)(mDensity * 8), |
||||||
|
widgetFrameView.getPaddingBottom() |
||||||
|
); |
||||||
|
// remove already create preview image
|
||||||
|
int count = widgetFrameView.getChildCount(); |
||||||
|
if (count > 0) { |
||||||
|
widgetFrameView.removeViews(0, count); |
||||||
|
} |
||||||
|
widgetFrameView.addView(iView); |
||||||
|
widgetFrameView.setMinimumWidth(0); |
||||||
|
iView.setBackgroundDrawable(new AlphaPatternDrawable((int)(5 * mDensity))); |
||||||
|
iView.setImageBitmap(getPreviewBitmap()); |
||||||
|
} |
||||||
|
|
||||||
|
private Bitmap getPreviewBitmap() { |
||||||
|
int d = (int) (mDensity * 31); //30dip
|
||||||
|
int color = mValue; |
||||||
|
Bitmap bm = Bitmap.createBitmap(d, d, Config.ARGB_8888); |
||||||
|
int w = bm.getWidth(); |
||||||
|
int h = bm.getHeight(); |
||||||
|
int c = color; |
||||||
|
for (int i = 0; i < w; i++) { |
||||||
|
for (int j = i; j < h; j++) { |
||||||
|
c = (i <= 1 || j <= 1 || i >= w-2 || j >= h-2) ? Color.GRAY : color; |
||||||
|
bm.setPixel(i, j, c); |
||||||
|
if (i != j) { |
||||||
|
bm.setPixel(j, i, c); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return bm; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onColorChanged(int color) { |
||||||
|
if (isPersistent()) { |
||||||
|
persistInt(color); |
||||||
|
} |
||||||
|
mValue = color; |
||||||
|
setPreviewColor(); |
||||||
|
try { |
||||||
|
getOnPreferenceChangeListener().onPreferenceChange(this, color); |
||||||
|
} catch (NullPointerException e) { |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean onPreferenceClick(Preference preference) { |
||||||
|
showDialog(null); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
protected void showDialog(Bundle state) { |
||||||
|
mDialog = new ColorPickerDialog(getContext(), mValue); |
||||||
|
mDialog.setOnColorChangedListener(this); |
||||||
|
if (mAlphaSliderEnabled) { |
||||||
|
mDialog.setAlphaSliderVisible(true); |
||||||
|
} |
||||||
|
if (state != null) { |
||||||
|
mDialog.onRestoreInstanceState(state); |
||||||
|
} |
||||||
|
mDialog.show(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Toggle Alpha Slider visibility (by default it's disabled) |
||||||
|
* @param enable |
||||||
|
*/ |
||||||
|
public void setAlphaSliderEnabled(boolean enable) { |
||||||
|
mAlphaSliderEnabled = enable; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* For custom purposes. Not used by ColorPickerPreferrence |
||||||
|
* @param color |
||||||
|
* @author Unknown |
||||||
|
*/ |
||||||
|
public static String convertToARGB(int color) { |
||||||
|
String alpha = Integer.toHexString(Color.alpha(color)); |
||||||
|
String red = Integer.toHexString(Color.red(color)); |
||||||
|
String green = Integer.toHexString(Color.green(color)); |
||||||
|
String blue = Integer.toHexString(Color.blue(color)); |
||||||
|
|
||||||
|
if (alpha.length() == 1) { |
||||||
|
alpha = "0" + alpha; |
||||||
|
} |
||||||
|
|
||||||
|
if (red.length() == 1) { |
||||||
|
red = "0" + red; |
||||||
|
} |
||||||
|
|
||||||
|
if (green.length() == 1) { |
||||||
|
green = "0" + green; |
||||||
|
} |
||||||
|
|
||||||
|
if (blue.length() == 1) { |
||||||
|
blue = "0" + blue; |
||||||
|
} |
||||||
|
|
||||||
|
return "#" + alpha + red + green + blue; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* For custom purposes. Not used by ColorPickerPreferrence |
||||||
|
* @param argb |
||||||
|
* @throws NumberFormatException |
||||||
|
* @author Unknown |
||||||
|
*/ |
||||||
|
public static int convertToColorInt(String argb) throws NumberFormatException { |
||||||
|
|
||||||
|
if (argb.startsWith("#")) { |
||||||
|
argb = argb.replace("#", ""); |
||||||
|
} |
||||||
|
|
||||||
|
int alpha = -1, red = -1, green = -1, blue = -1; |
||||||
|
|
||||||
|
if (argb.length() == 8) { |
||||||
|
alpha = Integer.parseInt(argb.substring(0, 2), 16); |
||||||
|
red = Integer.parseInt(argb.substring(2, 4), 16); |
||||||
|
green = Integer.parseInt(argb.substring(4, 6), 16); |
||||||
|
blue = Integer.parseInt(argb.substring(6, 8), 16); |
||||||
|
} |
||||||
|
else if (argb.length() == 6) { |
||||||
|
alpha = 255; |
||||||
|
red = Integer.parseInt(argb.substring(0, 2), 16); |
||||||
|
green = Integer.parseInt(argb.substring(2, 4), 16); |
||||||
|
blue = Integer.parseInt(argb.substring(4, 6), 16); |
||||||
|
} |
||||||
|
|
||||||
|
return Color.argb(alpha, red, green, blue); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Parcelable onSaveInstanceState() { |
||||||
|
final Parcelable superState = super.onSaveInstanceState(); |
||||||
|
if (mDialog == null || !mDialog.isShowing()) { |
||||||
|
return superState; |
||||||
|
} |
||||||
|
|
||||||
|
final SavedState myState = new SavedState(superState); |
||||||
|
myState.dialogBundle = mDialog.onSaveInstanceState(); |
||||||
|
return myState; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onRestoreInstanceState(Parcelable state) { |
||||||
|
if (state == null || !(state instanceof SavedState)) { |
||||||
|
// Didn't save state for us in onSaveInstanceState
|
||||||
|
super.onRestoreInstanceState(state); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
SavedState myState = (SavedState) state; |
||||||
|
super.onRestoreInstanceState(myState.getSuperState()); |
||||||
|
showDialog(myState.dialogBundle); |
||||||
|
} |
||||||
|
|
||||||
|
private static class SavedState extends BaseSavedState { |
||||||
|
Bundle dialogBundle; |
||||||
|
|
||||||
|
public SavedState(Parcel source) { |
||||||
|
super(source); |
||||||
|
dialogBundle = source.readBundle(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void writeToParcel(Parcel dest, int flags) { |
||||||
|
super.writeToParcel(dest, flags); |
||||||
|
dest.writeBundle(dialogBundle); |
||||||
|
} |
||||||
|
|
||||||
|
public SavedState(Parcelable superState) { |
||||||
|
super(superState); |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("unused") |
||||||
|
public static final Parcelable.Creator<SavedState> CREATOR = |
||||||
|
new Parcelable.Creator<SavedState>() { |
||||||
|
public SavedState createFromParcel(Parcel in) { |
||||||
|
return new SavedState(in); |
||||||
|
} |
||||||
|
|
||||||
|
public SavedState[] newArray(int size) { |
||||||
|
return new SavedState[size]; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,952 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2010 Daniel Nilsson |
||||||
|
* |
||||||
|
* 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 net.margaritov.preference.colorpicker; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Color; |
||||||
|
import android.graphics.ComposeShader; |
||||||
|
import android.graphics.LinearGradient; |
||||||
|
import android.graphics.Paint; |
||||||
|
import android.graphics.Point; |
||||||
|
import android.graphics.PorterDuff; |
||||||
|
import android.graphics.RectF; |
||||||
|
import android.graphics.Shader; |
||||||
|
import android.graphics.Paint.Align; |
||||||
|
import android.graphics.Paint.Style; |
||||||
|
import android.graphics.Shader.TileMode; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
/** |
||||||
|
* Displays a color picker to the user and allow them |
||||||
|
* to select a color. A slider for the alpha channel is |
||||||
|
* also available. Enable it by setting |
||||||
|
* setAlphaSliderVisible(boolean) to true. |
||||||
|
* @author Daniel Nilsson |
||||||
|
*/ |
||||||
|
public class ColorPickerView extends View { |
||||||
|
|
||||||
|
private final static int PANEL_SAT_VAL = 0; |
||||||
|
private final static int PANEL_HUE = 1; |
||||||
|
private final static int PANEL_ALPHA = 2; |
||||||
|
|
||||||
|
/** |
||||||
|
* The width in pixels of the border |
||||||
|
* surrounding all color panels. |
||||||
|
*/ |
||||||
|
private final static float BORDER_WIDTH_PX = 1; |
||||||
|
|
||||||
|
/** |
||||||
|
* The width in dp of the hue panel. |
||||||
|
*/ |
||||||
|
private float HUE_PANEL_WIDTH = 30f; |
||||||
|
/** |
||||||
|
* The height in dp of the alpha panel |
||||||
|
*/ |
||||||
|
private float ALPHA_PANEL_HEIGHT = 20f; |
||||||
|
/** |
||||||
|
* The distance in dp between the different |
||||||
|
* color panels. |
||||||
|
*/ |
||||||
|
private float PANEL_SPACING = 10f; |
||||||
|
/** |
||||||
|
* The radius in dp of the color palette tracker circle. |
||||||
|
*/ |
||||||
|
private float PALETTE_CIRCLE_TRACKER_RADIUS = 5f; |
||||||
|
/** |
||||||
|
* The dp which the tracker of the hue or alpha panel |
||||||
|
* will extend outside of its bounds. |
||||||
|
*/ |
||||||
|
private float RECTANGLE_TRACKER_OFFSET = 2f; |
||||||
|
|
||||||
|
|
||||||
|
private float mDensity = 1f; |
||||||
|
|
||||||
|
private OnColorChangedListener mListener; |
||||||
|
|
||||||
|
private Paint mSatValPaint; |
||||||
|
private Paint mSatValTrackerPaint; |
||||||
|
|
||||||
|
private Paint mHuePaint; |
||||||
|
private Paint mHueTrackerPaint; |
||||||
|
|
||||||
|
private Paint mAlphaPaint; |
||||||
|
private Paint mAlphaTextPaint; |
||||||
|
|
||||||
|
private Paint mBorderPaint; |
||||||
|
|
||||||
|
private Shader mValShader; |
||||||
|
private Shader mSatShader; |
||||||
|
private Shader mHueShader; |
||||||
|
private Shader mAlphaShader; |
||||||
|
|
||||||
|
private int mAlpha = 0xff; |
||||||
|
private float mHue = 360f; |
||||||
|
private float mSat = 0f; |
||||||
|
private float mVal = 0f; |
||||||
|
|
||||||
|
private String mAlphaSliderText = ""; |
||||||
|
private int mSliderTrackerColor = 0xff1c1c1c; |
||||||
|
private int mBorderColor = 0xff6E6E6E; |
||||||
|
private boolean mShowAlphaPanel = false; |
||||||
|
|
||||||
|
/* |
||||||
|
* To remember which panel that has the "focus" when |
||||||
|
* processing hardware button data. |
||||||
|
*/ |
||||||
|
private int mLastTouchedPanel = PANEL_SAT_VAL; |
||||||
|
|
||||||
|
/** |
||||||
|
* Offset from the edge we must have or else |
||||||
|
* the finger tracker will get clipped when |
||||||
|
* it is drawn outside of the view. |
||||||
|
*/ |
||||||
|
private float mDrawingOffset; |
||||||
|
|
||||||
|
|
||||||
|
/* |
||||||
|
* Distance form the edges of the view |
||||||
|
* of where we are allowed to draw. |
||||||
|
*/ |
||||||
|
private RectF mDrawingRect; |
||||||
|
|
||||||
|
private RectF mSatValRect; |
||||||
|
private RectF mHueRect; |
||||||
|
private RectF mAlphaRect; |
||||||
|
|
||||||
|
private AlphaPatternDrawable mAlphaPattern; |
||||||
|
|
||||||
|
private Point mStartTouchPoint = null; |
||||||
|
|
||||||
|
public interface OnColorChangedListener { |
||||||
|
public void onColorChanged(int color); |
||||||
|
} |
||||||
|
|
||||||
|
public ColorPickerView(Context context){ |
||||||
|
this(context, null); |
||||||
|
} |
||||||
|
|
||||||
|
public ColorPickerView(Context context, AttributeSet attrs) { |
||||||
|
this(context, attrs, 0); |
||||||
|
} |
||||||
|
|
||||||
|
public ColorPickerView(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
private void init(){ |
||||||
|
mDensity = getContext().getResources().getDisplayMetrics().density; |
||||||
|
PALETTE_CIRCLE_TRACKER_RADIUS *= mDensity; |
||||||
|
RECTANGLE_TRACKER_OFFSET *= mDensity; |
||||||
|
HUE_PANEL_WIDTH *= mDensity; |
||||||
|
ALPHA_PANEL_HEIGHT *= mDensity; |
||||||
|
PANEL_SPACING = PANEL_SPACING * mDensity; |
||||||
|
|
||||||
|
mDrawingOffset = calculateRequiredOffset(); |
||||||
|
|
||||||
|
initPaintTools(); |
||||||
|
|
||||||
|
//Needed for receiving trackball motion events.
|
||||||
|
setFocusable(true); |
||||||
|
setFocusableInTouchMode(true); |
||||||
|
} |
||||||
|
|
||||||
|
private void initPaintTools(){ |
||||||
|
|
||||||
|
mSatValPaint = new Paint(); |
||||||
|
mSatValTrackerPaint = new Paint(); |
||||||
|
mHuePaint = new Paint(); |
||||||
|
mHueTrackerPaint = new Paint(); |
||||||
|
mAlphaPaint = new Paint(); |
||||||
|
mAlphaTextPaint = new Paint(); |
||||||
|
mBorderPaint = new Paint(); |
||||||
|
|
||||||
|
|
||||||
|
mSatValTrackerPaint.setStyle(Style.STROKE); |
||||||
|
mSatValTrackerPaint.setStrokeWidth(2f * mDensity); |
||||||
|
mSatValTrackerPaint.setAntiAlias(true); |
||||||
|
|
||||||
|
mHueTrackerPaint.setColor(mSliderTrackerColor); |
||||||
|
mHueTrackerPaint.setStyle(Style.STROKE); |
||||||
|
mHueTrackerPaint.setStrokeWidth(2f * mDensity); |
||||||
|
mHueTrackerPaint.setAntiAlias(true); |
||||||
|
|
||||||
|
mAlphaTextPaint.setColor(0xff1c1c1c); |
||||||
|
mAlphaTextPaint.setTextSize(14f * mDensity); |
||||||
|
mAlphaTextPaint.setAntiAlias(true); |
||||||
|
mAlphaTextPaint.setTextAlign(Align.CENTER); |
||||||
|
mAlphaTextPaint.setFakeBoldText(true); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private float calculateRequiredOffset(){ |
||||||
|
float offset = Math.max(PALETTE_CIRCLE_TRACKER_RADIUS, RECTANGLE_TRACKER_OFFSET); |
||||||
|
offset = Math.max(offset, BORDER_WIDTH_PX * mDensity); |
||||||
|
|
||||||
|
return offset * 1.5f; |
||||||
|
} |
||||||
|
|
||||||
|
private int[] buildHueColorArray(){ |
||||||
|
|
||||||
|
int[] hue = new int[361]; |
||||||
|
|
||||||
|
int count = 0; |
||||||
|
for(int i = hue.length -1; i >= 0; i--, count++){ |
||||||
|
hue[count] = Color.HSVToColor(new float[]{i, 1f, 1f}); |
||||||
|
} |
||||||
|
|
||||||
|
return hue; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onDraw(Canvas canvas) { |
||||||
|
|
||||||
|
if(mDrawingRect.width() <= 0 || mDrawingRect.height() <= 0) return; |
||||||
|
|
||||||
|
drawSatValPanel(canvas); |
||||||
|
drawHuePanel(canvas); |
||||||
|
drawAlphaPanel(canvas); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void drawSatValPanel(Canvas canvas){ |
||||||
|
|
||||||
|
final RectF rect = mSatValRect; |
||||||
|
|
||||||
|
if(BORDER_WIDTH_PX > 0){ |
||||||
|
mBorderPaint.setColor(mBorderColor); |
||||||
|
canvas.drawRect(mDrawingRect.left, mDrawingRect.top, rect.right + BORDER_WIDTH_PX, rect.bottom + BORDER_WIDTH_PX, mBorderPaint); |
||||||
|
} |
||||||
|
|
||||||
|
if (mValShader == null) { |
||||||
|
mValShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, |
||||||
|
0xffffffff, 0xff000000, TileMode.CLAMP); |
||||||
|
} |
||||||
|
|
||||||
|
int rgb = Color.HSVToColor(new float[]{mHue,1f,1f}); |
||||||
|
|
||||||
|
mSatShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top, |
||||||
|
0xffffffff, rgb, TileMode.CLAMP); |
||||||
|
ComposeShader mShader = new ComposeShader(mValShader, mSatShader, PorterDuff.Mode.MULTIPLY); |
||||||
|
mSatValPaint.setShader(mShader); |
||||||
|
|
||||||
|
canvas.drawRect(rect, mSatValPaint); |
||||||
|
|
||||||
|
Point p = satValToPoint(mSat, mVal); |
||||||
|
|
||||||
|
mSatValTrackerPaint.setColor(0xff000000); |
||||||
|
canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS - 1f * mDensity, mSatValTrackerPaint); |
||||||
|
|
||||||
|
mSatValTrackerPaint.setColor(0xffdddddd); |
||||||
|
canvas.drawCircle(p.x, p.y, PALETTE_CIRCLE_TRACKER_RADIUS, mSatValTrackerPaint); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void drawHuePanel(Canvas canvas){ |
||||||
|
|
||||||
|
final RectF rect = mHueRect; |
||||||
|
|
||||||
|
if(BORDER_WIDTH_PX > 0){ |
||||||
|
mBorderPaint.setColor(mBorderColor); |
||||||
|
canvas.drawRect(rect.left - BORDER_WIDTH_PX, |
||||||
|
rect.top - BORDER_WIDTH_PX, |
||||||
|
rect.right + BORDER_WIDTH_PX, |
||||||
|
rect.bottom + BORDER_WIDTH_PX, |
||||||
|
mBorderPaint); |
||||||
|
} |
||||||
|
|
||||||
|
if (mHueShader == null) { |
||||||
|
mHueShader = new LinearGradient(rect.left, rect.top, rect.left, rect.bottom, buildHueColorArray(), null, TileMode.CLAMP); |
||||||
|
mHuePaint.setShader(mHueShader); |
||||||
|
} |
||||||
|
|
||||||
|
canvas.drawRect(rect, mHuePaint); |
||||||
|
|
||||||
|
float rectHeight = 4 * mDensity / 2; |
||||||
|
|
||||||
|
Point p = hueToPoint(mHue); |
||||||
|
|
||||||
|
RectF r = new RectF(); |
||||||
|
r.left = rect.left - RECTANGLE_TRACKER_OFFSET; |
||||||
|
r.right = rect.right + RECTANGLE_TRACKER_OFFSET; |
||||||
|
r.top = p.y - rectHeight; |
||||||
|
r.bottom = p.y + rectHeight; |
||||||
|
|
||||||
|
|
||||||
|
canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void drawAlphaPanel(Canvas canvas){ |
||||||
|
|
||||||
|
if(!mShowAlphaPanel || mAlphaRect == null || mAlphaPattern == null) return; |
||||||
|
|
||||||
|
final RectF rect = mAlphaRect; |
||||||
|
|
||||||
|
if(BORDER_WIDTH_PX > 0){ |
||||||
|
mBorderPaint.setColor(mBorderColor); |
||||||
|
canvas.drawRect(rect.left - BORDER_WIDTH_PX, |
||||||
|
rect.top - BORDER_WIDTH_PX, |
||||||
|
rect.right + BORDER_WIDTH_PX, |
||||||
|
rect.bottom + BORDER_WIDTH_PX, |
||||||
|
mBorderPaint); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
mAlphaPattern.draw(canvas); |
||||||
|
|
||||||
|
float[] hsv = new float[]{mHue,mSat,mVal}; |
||||||
|
int color = Color.HSVToColor(hsv); |
||||||
|
int acolor = Color.HSVToColor(0, hsv); |
||||||
|
|
||||||
|
mAlphaShader = new LinearGradient(rect.left, rect.top, rect.right, rect.top, |
||||||
|
color, acolor, TileMode.CLAMP); |
||||||
|
|
||||||
|
|
||||||
|
mAlphaPaint.setShader(mAlphaShader); |
||||||
|
|
||||||
|
canvas.drawRect(rect, mAlphaPaint); |
||||||
|
|
||||||
|
if(mAlphaSliderText != null && mAlphaSliderText!= ""){ |
||||||
|
canvas.drawText(mAlphaSliderText, rect.centerX(), rect.centerY() + 4 * mDensity, mAlphaTextPaint); |
||||||
|
} |
||||||
|
|
||||||
|
float rectWidth = 4 * mDensity / 2; |
||||||
|
|
||||||
|
Point p = alphaToPoint(mAlpha); |
||||||
|
|
||||||
|
RectF r = new RectF(); |
||||||
|
r.left = p.x - rectWidth; |
||||||
|
r.right = p.x + rectWidth; |
||||||
|
r.top = rect.top - RECTANGLE_TRACKER_OFFSET; |
||||||
|
r.bottom = rect.bottom + RECTANGLE_TRACKER_OFFSET; |
||||||
|
|
||||||
|
canvas.drawRoundRect(r, 2, 2, mHueTrackerPaint); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private Point hueToPoint(float hue){ |
||||||
|
|
||||||
|
final RectF rect = mHueRect; |
||||||
|
final float height = rect.height(); |
||||||
|
|
||||||
|
Point p = new Point(); |
||||||
|
|
||||||
|
p.y = (int) (height - (hue * height / 360f) + rect.top); |
||||||
|
p.x = (int) rect.left; |
||||||
|
|
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
private Point satValToPoint(float sat, float val){ |
||||||
|
|
||||||
|
final RectF rect = mSatValRect; |
||||||
|
final float height = rect.height(); |
||||||
|
final float width = rect.width(); |
||||||
|
|
||||||
|
Point p = new Point(); |
||||||
|
|
||||||
|
p.x = (int) (sat * width + rect.left); |
||||||
|
p.y = (int) ((1f - val) * height + rect.top); |
||||||
|
|
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
private Point alphaToPoint(int alpha){ |
||||||
|
|
||||||
|
final RectF rect = mAlphaRect; |
||||||
|
final float width = rect.width(); |
||||||
|
|
||||||
|
Point p = new Point(); |
||||||
|
|
||||||
|
p.x = (int) (width - (alpha * width / 0xff) + rect.left); |
||||||
|
p.y = (int) rect.top; |
||||||
|
|
||||||
|
return p; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private float[] pointToSatVal(float x, float y){ |
||||||
|
|
||||||
|
final RectF rect = mSatValRect; |
||||||
|
float[] result = new float[2]; |
||||||
|
|
||||||
|
float width = rect.width(); |
||||||
|
float height = rect.height(); |
||||||
|
|
||||||
|
if (x < rect.left){ |
||||||
|
x = 0f; |
||||||
|
} |
||||||
|
else if(x > rect.right){ |
||||||
|
x = width; |
||||||
|
} |
||||||
|
else{ |
||||||
|
x = x - rect.left; |
||||||
|
} |
||||||
|
|
||||||
|
if (y < rect.top){ |
||||||
|
y = 0f; |
||||||
|
} |
||||||
|
else if(y > rect.bottom){ |
||||||
|
y = height; |
||||||
|
} |
||||||
|
else{ |
||||||
|
y = y - rect.top; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
result[0] = 1.f / width * x; |
||||||
|
result[1] = 1.f - (1.f / height * y); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
private float pointToHue(float y){ |
||||||
|
|
||||||
|
final RectF rect = mHueRect; |
||||||
|
|
||||||
|
float height = rect.height(); |
||||||
|
|
||||||
|
if (y < rect.top){ |
||||||
|
y = 0f; |
||||||
|
} |
||||||
|
else if(y > rect.bottom){ |
||||||
|
y = height; |
||||||
|
} |
||||||
|
else{ |
||||||
|
y = y - rect.top; |
||||||
|
} |
||||||
|
|
||||||
|
return 360f - (y * 360f / height); |
||||||
|
} |
||||||
|
|
||||||
|
private int pointToAlpha(int x){ |
||||||
|
|
||||||
|
final RectF rect = mAlphaRect; |
||||||
|
final int width = (int) rect.width(); |
||||||
|
|
||||||
|
if(x < rect.left){ |
||||||
|
x = 0; |
||||||
|
} |
||||||
|
else if(x > rect.right){ |
||||||
|
x = width; |
||||||
|
} |
||||||
|
else{ |
||||||
|
x = x - (int)rect.left; |
||||||
|
} |
||||||
|
|
||||||
|
return 0xff - (x * 0xff / width); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onTrackballEvent(MotionEvent event) { |
||||||
|
|
||||||
|
float x = event.getX(); |
||||||
|
float y = event.getY(); |
||||||
|
|
||||||
|
boolean update = false; |
||||||
|
|
||||||
|
|
||||||
|
if(event.getAction() == MotionEvent.ACTION_MOVE){ |
||||||
|
|
||||||
|
switch(mLastTouchedPanel){ |
||||||
|
|
||||||
|
case PANEL_SAT_VAL: |
||||||
|
|
||||||
|
float sat, val; |
||||||
|
|
||||||
|
sat = mSat + x/50f; |
||||||
|
val = mVal - y/50f; |
||||||
|
|
||||||
|
if(sat < 0f){ |
||||||
|
sat = 0f; |
||||||
|
} |
||||||
|
else if(sat > 1f){ |
||||||
|
sat = 1f; |
||||||
|
} |
||||||
|
|
||||||
|
if(val < 0f){ |
||||||
|
val = 0f; |
||||||
|
} |
||||||
|
else if(val > 1f){ |
||||||
|
val = 1f; |
||||||
|
} |
||||||
|
|
||||||
|
mSat = sat; |
||||||
|
mVal = val; |
||||||
|
|
||||||
|
update = true; |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
case PANEL_HUE: |
||||||
|
|
||||||
|
float hue = mHue - y * 10f; |
||||||
|
|
||||||
|
if(hue < 0f){ |
||||||
|
hue = 0f; |
||||||
|
} |
||||||
|
else if(hue > 360f){ |
||||||
|
hue = 360f; |
||||||
|
} |
||||||
|
|
||||||
|
mHue = hue; |
||||||
|
|
||||||
|
update = true; |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
case PANEL_ALPHA: |
||||||
|
|
||||||
|
if(!mShowAlphaPanel || mAlphaRect == null){ |
||||||
|
update = false; |
||||||
|
} |
||||||
|
else{ |
||||||
|
|
||||||
|
int alpha = (int) (mAlpha - x*10); |
||||||
|
|
||||||
|
if(alpha < 0){ |
||||||
|
alpha = 0; |
||||||
|
} |
||||||
|
else if(alpha > 0xff){ |
||||||
|
alpha = 0xff; |
||||||
|
} |
||||||
|
|
||||||
|
mAlpha = alpha; |
||||||
|
|
||||||
|
|
||||||
|
update = true; |
||||||
|
} |
||||||
|
|
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
if(update){ |
||||||
|
|
||||||
|
if(mListener != null){ |
||||||
|
mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal})); |
||||||
|
} |
||||||
|
|
||||||
|
invalidate(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return super.onTrackballEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onTouchEvent(MotionEvent event) { |
||||||
|
|
||||||
|
boolean update = false; |
||||||
|
|
||||||
|
switch(event.getAction()){ |
||||||
|
|
||||||
|
case MotionEvent.ACTION_DOWN: |
||||||
|
|
||||||
|
mStartTouchPoint = new Point((int)event.getX(), (int)event.getY()); |
||||||
|
|
||||||
|
update = moveTrackersIfNeeded(event); |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
case MotionEvent.ACTION_MOVE: |
||||||
|
|
||||||
|
update = moveTrackersIfNeeded(event); |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
case MotionEvent.ACTION_UP: |
||||||
|
|
||||||
|
mStartTouchPoint = null; |
||||||
|
|
||||||
|
update = moveTrackersIfNeeded(event); |
||||||
|
|
||||||
|
break; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if(update){ |
||||||
|
|
||||||
|
if(mListener != null){ |
||||||
|
mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal})); |
||||||
|
} |
||||||
|
|
||||||
|
invalidate(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return super.onTouchEvent(event); |
||||||
|
} |
||||||
|
|
||||||
|
private boolean moveTrackersIfNeeded(MotionEvent event){ |
||||||
|
|
||||||
|
if(mStartTouchPoint == null) return false; |
||||||
|
|
||||||
|
boolean update = false; |
||||||
|
|
||||||
|
int startX = mStartTouchPoint.x; |
||||||
|
int startY = mStartTouchPoint.y; |
||||||
|
|
||||||
|
|
||||||
|
if(mHueRect.contains(startX, startY)){ |
||||||
|
mLastTouchedPanel = PANEL_HUE; |
||||||
|
|
||||||
|
mHue = pointToHue(event.getY()); |
||||||
|
|
||||||
|
update = true; |
||||||
|
} |
||||||
|
else if(mSatValRect.contains(startX, startY)){ |
||||||
|
|
||||||
|
mLastTouchedPanel = PANEL_SAT_VAL; |
||||||
|
|
||||||
|
float[] result = pointToSatVal(event.getX(), event.getY()); |
||||||
|
|
||||||
|
mSat = result[0]; |
||||||
|
mVal = result[1]; |
||||||
|
|
||||||
|
update = true; |
||||||
|
} |
||||||
|
else if(mAlphaRect != null && mAlphaRect.contains(startX, startY)){ |
||||||
|
|
||||||
|
mLastTouchedPanel = PANEL_ALPHA; |
||||||
|
|
||||||
|
mAlpha = pointToAlpha((int)event.getX()); |
||||||
|
|
||||||
|
update = true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return update; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
||||||
|
|
||||||
|
int width = 0; |
||||||
|
int height = 0; |
||||||
|
|
||||||
|
int widthMode = MeasureSpec.getMode(widthMeasureSpec); |
||||||
|
int heightMode = MeasureSpec.getMode(heightMeasureSpec); |
||||||
|
|
||||||
|
int widthAllowed = MeasureSpec.getSize(widthMeasureSpec); |
||||||
|
int heightAllowed = MeasureSpec.getSize(heightMeasureSpec); |
||||||
|
|
||||||
|
widthAllowed = chooseWidth(widthMode, widthAllowed); |
||||||
|
heightAllowed = chooseHeight(heightMode, heightAllowed); |
||||||
|
|
||||||
|
if(!mShowAlphaPanel){ |
||||||
|
|
||||||
|
height = (int) (widthAllowed - PANEL_SPACING - HUE_PANEL_WIDTH); |
||||||
|
|
||||||
|
//If calculated height (based on the width) is more than the allowed height.
|
||||||
|
if(height > heightAllowed || getTag().equals("landscape")) { |
||||||
|
height = heightAllowed; |
||||||
|
width = (int) (height + PANEL_SPACING + HUE_PANEL_WIDTH); |
||||||
|
} |
||||||
|
else{ |
||||||
|
width = widthAllowed; |
||||||
|
} |
||||||
|
} |
||||||
|
else{ |
||||||
|
|
||||||
|
width = (int) (heightAllowed - ALPHA_PANEL_HEIGHT + HUE_PANEL_WIDTH); |
||||||
|
|
||||||
|
if(width > widthAllowed){ |
||||||
|
width = widthAllowed; |
||||||
|
height = (int) (widthAllowed - HUE_PANEL_WIDTH + ALPHA_PANEL_HEIGHT); |
||||||
|
} |
||||||
|
else{ |
||||||
|
height = heightAllowed; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
setMeasuredDimension(width, height); |
||||||
|
} |
||||||
|
|
||||||
|
private int chooseWidth(int mode, int size){ |
||||||
|
if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) { |
||||||
|
return size; |
||||||
|
} else { // (mode == MeasureSpec.UNSPECIFIED)
|
||||||
|
return getPrefferedWidth(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private int chooseHeight(int mode, int size){ |
||||||
|
if (mode == MeasureSpec.AT_MOST || mode == MeasureSpec.EXACTLY) { |
||||||
|
return size; |
||||||
|
} else { // (mode == MeasureSpec.UNSPECIFIED)
|
||||||
|
return getPrefferedHeight(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private int getPrefferedWidth(){ |
||||||
|
|
||||||
|
int width = getPrefferedHeight(); |
||||||
|
|
||||||
|
if(mShowAlphaPanel){ |
||||||
|
width -= (PANEL_SPACING + ALPHA_PANEL_HEIGHT); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return (int) (width + HUE_PANEL_WIDTH + PANEL_SPACING); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private int getPrefferedHeight(){ |
||||||
|
|
||||||
|
int height = (int)(200 * mDensity); |
||||||
|
|
||||||
|
if(mShowAlphaPanel){ |
||||||
|
height += PANEL_SPACING + ALPHA_PANEL_HEIGHT; |
||||||
|
} |
||||||
|
|
||||||
|
return height; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
||||||
|
super.onSizeChanged(w, h, oldw, oldh); |
||||||
|
|
||||||
|
mDrawingRect = new RectF(); |
||||||
|
mDrawingRect.left = mDrawingOffset + getPaddingLeft(); |
||||||
|
mDrawingRect.right = w - mDrawingOffset - getPaddingRight(); |
||||||
|
mDrawingRect.top = mDrawingOffset + getPaddingTop(); |
||||||
|
mDrawingRect.bottom = h - mDrawingOffset - getPaddingBottom(); |
||||||
|
|
||||||
|
setUpSatValRect(); |
||||||
|
setUpHueRect(); |
||||||
|
setUpAlphaRect(); |
||||||
|
} |
||||||
|
|
||||||
|
private void setUpSatValRect(){ |
||||||
|
|
||||||
|
final RectF dRect = mDrawingRect; |
||||||
|
float panelSide = dRect.height() - BORDER_WIDTH_PX * 2; |
||||||
|
|
||||||
|
if(mShowAlphaPanel){ |
||||||
|
panelSide -= PANEL_SPACING + ALPHA_PANEL_HEIGHT; |
||||||
|
} |
||||||
|
|
||||||
|
float left = dRect.left + BORDER_WIDTH_PX; |
||||||
|
float top = dRect.top + BORDER_WIDTH_PX; |
||||||
|
float bottom = top + panelSide; |
||||||
|
float right = left + panelSide; |
||||||
|
|
||||||
|
mSatValRect = new RectF(left,top, right, bottom); |
||||||
|
} |
||||||
|
|
||||||
|
private void setUpHueRect(){ |
||||||
|
final RectF dRect = mDrawingRect; |
||||||
|
|
||||||
|
float left = dRect.right - HUE_PANEL_WIDTH + BORDER_WIDTH_PX; |
||||||
|
float top = dRect.top + BORDER_WIDTH_PX; |
||||||
|
float bottom = dRect.bottom - BORDER_WIDTH_PX - (mShowAlphaPanel ? (PANEL_SPACING + ALPHA_PANEL_HEIGHT) : 0); |
||||||
|
float right = dRect.right - BORDER_WIDTH_PX; |
||||||
|
|
||||||
|
mHueRect = new RectF(left, top, right, bottom); |
||||||
|
} |
||||||
|
|
||||||
|
private void setUpAlphaRect() { |
||||||
|
|
||||||
|
if(!mShowAlphaPanel) return; |
||||||
|
|
||||||
|
final RectF dRect = mDrawingRect; |
||||||
|
|
||||||
|
float left = dRect.left + BORDER_WIDTH_PX; |
||||||
|
float top = dRect.bottom - ALPHA_PANEL_HEIGHT + BORDER_WIDTH_PX; |
||||||
|
float bottom = dRect.bottom - BORDER_WIDTH_PX; |
||||||
|
float right = dRect.right - BORDER_WIDTH_PX; |
||||||
|
|
||||||
|
mAlphaRect = new RectF(left, top, right, bottom); |
||||||
|
|
||||||
|
mAlphaPattern = new AlphaPatternDrawable((int) (5 * mDensity)); |
||||||
|
mAlphaPattern.setBounds( |
||||||
|
Math.round(mAlphaRect.left), |
||||||
|
Math.round(mAlphaRect.top), |
||||||
|
Math.round(mAlphaRect.right), |
||||||
|
Math.round(mAlphaRect.bottom) |
||||||
|
); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Set a OnColorChangedListener to get notified when the color |
||||||
|
* selected by the user has changed. |
||||||
|
* @param listener |
||||||
|
*/ |
||||||
|
public void setOnColorChangedListener(OnColorChangedListener listener){ |
||||||
|
mListener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the color of the border surrounding all panels. |
||||||
|
* @param color |
||||||
|
*/ |
||||||
|
public void setBorderColor(int color){ |
||||||
|
mBorderColor = color; |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the color of the border surrounding all panels. |
||||||
|
*/ |
||||||
|
public int getBorderColor(){ |
||||||
|
return mBorderColor; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the current color this view is showing. |
||||||
|
* @return the current color. |
||||||
|
*/ |
||||||
|
public int getColor(){ |
||||||
|
return Color.HSVToColor(mAlpha, new float[]{mHue,mSat,mVal}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the color the view should show. |
||||||
|
* @param color The color that should be selected. |
||||||
|
*/ |
||||||
|
public void setColor(int color){ |
||||||
|
setColor(color, false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the color this view should show. |
||||||
|
* @param color The color that should be selected. |
||||||
|
* @param callback If you want to get a callback to |
||||||
|
* your OnColorChangedListener. |
||||||
|
*/ |
||||||
|
public void setColor(int color, boolean callback){ |
||||||
|
|
||||||
|
int alpha = Color.alpha(color); |
||||||
|
int red = Color.red(color); |
||||||
|
int blue = Color.blue(color); |
||||||
|
int green = Color.green(color); |
||||||
|
|
||||||
|
float[] hsv = new float[3]; |
||||||
|
|
||||||
|
Color.RGBToHSV(red, green, blue, hsv); |
||||||
|
|
||||||
|
mAlpha = alpha; |
||||||
|
mHue = hsv[0]; |
||||||
|
mSat = hsv[1]; |
||||||
|
mVal = hsv[2]; |
||||||
|
|
||||||
|
if(callback && mListener != null){ |
||||||
|
mListener.onColorChanged(Color.HSVToColor(mAlpha, new float[]{mHue, mSat, mVal})); |
||||||
|
} |
||||||
|
|
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the drawing offset of the color picker view. |
||||||
|
* The drawing offset is the distance from the side of |
||||||
|
* a panel to the side of the view minus the padding. |
||||||
|
* Useful if you want to have your own panel below showing |
||||||
|
* the currently selected color and want to align it perfectly. |
||||||
|
* @return The offset in pixels. |
||||||
|
*/ |
||||||
|
public float getDrawingOffset(){ |
||||||
|
return mDrawingOffset; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set if the user is allowed to adjust the alpha panel. Default is false. |
||||||
|
* If it is set to false no alpha will be set. |
||||||
|
* @param visible |
||||||
|
*/ |
||||||
|
public void setAlphaSliderVisible(boolean visible){ |
||||||
|
|
||||||
|
if(mShowAlphaPanel != visible){ |
||||||
|
mShowAlphaPanel = visible; |
||||||
|
|
||||||
|
/* |
||||||
|
* Reset all shader to force a recreation. |
||||||
|
* Otherwise they will not look right after |
||||||
|
* the size of the view has changed. |
||||||
|
*/ |
||||||
|
mValShader = null; |
||||||
|
mSatShader = null; |
||||||
|
mHueShader = null; |
||||||
|
mAlphaShader = null;; |
||||||
|
|
||||||
|
requestLayout(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void setSliderTrackerColor(int color){ |
||||||
|
mSliderTrackerColor = color; |
||||||
|
|
||||||
|
mHueTrackerPaint.setColor(mSliderTrackerColor); |
||||||
|
|
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getSliderTrackerColor(){ |
||||||
|
return mSliderTrackerColor; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the text that should be shown in the |
||||||
|
* alpha slider. Set to null to disable text. |
||||||
|
* @param res string resource id. |
||||||
|
*/ |
||||||
|
public void setAlphaSliderText(int res){ |
||||||
|
String text = getContext().getString(res); |
||||||
|
setAlphaSliderText(text); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the text that should be shown in the |
||||||
|
* alpha slider. Set to null to disable text. |
||||||
|
* @param text Text that should be shown. |
||||||
|
*/ |
||||||
|
public void setAlphaSliderText(String text){ |
||||||
|
mAlphaSliderText = text; |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the current value of the text |
||||||
|
* that will be shown in the alpha |
||||||
|
* slider. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public String getAlphaSliderText(){ |
||||||
|
return mAlphaSliderText; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2011 Sergey Margaritov |
||||||
|
* |
||||||
|
* 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 net.margaritov.preference.colorpicker; |
||||||
|
|
||||||
|
import net.margaritov.preference.colorpicker.R; |
||||||
|
|
||||||
|
import android.os.Bundle; |
||||||
|
import android.preference.Preference; |
||||||
|
import android.preference.Preference.OnPreferenceChangeListener; |
||||||
|
import android.preference.PreferenceActivity; |
||||||
|
|
||||||
|
public class Test extends PreferenceActivity { |
||||||
|
/** Called when the activity is first created. */ |
||||||
|
@Override |
||||||
|
public void onCreate(Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
addPreferencesFromResource(R.xml.settings); |
||||||
|
((ColorPickerPreference)findPreference("color2")).setOnPreferenceChangeListener(new OnPreferenceChangeListener() { |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) { |
||||||
|
preference.setSummary(ColorPickerPreference.convertToARGB(Integer.valueOf(String.valueOf(newValue)))); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
}); |
||||||
|
((ColorPickerPreference)findPreference("color2")).setAlphaSliderEnabled(true); |
||||||
|
} |
||||||
|
} |
@ -1,3 +1,3 @@ |
|||||||
<factorypath> |
<factorypath> |
||||||
<factorypathentry kind="WKSPJAR" id="/TransdroidLite/compile-libs/androidannotations-3.0-SNAPSHOT.jar" enabled="true" runInBatchMode="false"/> |
<factorypathentry kind="WKSPJAR" id="/Transdroid Core/compile-libs/androidannotations-3.0-SNAPSHOT.jar" enabled="true" runInBatchMode="false"/> |
||||||
</factorypath> |
</factorypath> |
||||||
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 848 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,89 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<fr.marvinlabs.widget.CheckableRelativeLayout |
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="fill_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:orientation="vertical" |
||||||
|
android:layout_marginTop="@dimen/margin_half" |
||||||
|
android:layout_marginBottom="@dimen/margin_half" |
||||||
|
android:layout_marginLeft="@dimen/margin_half" |
||||||
|
android:layout_marginRight="@dimen/margin_default"> |
||||||
|
|
||||||
|
<ImageView |
||||||
|
android:id="@+id/priority_image" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginLeft="@dimen/margin_half" |
||||||
|
android:layout_marginTop="@dimen/margin_half" |
||||||
|
android:src="@drawable/ic_priority_normal" /> |
||||||
|
|
||||||
|
<fr.marvinlabs.widget.InertCheckBox |
||||||
|
android:id="@+id/torrent_checkbox" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_below="@id/priority_image" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/name_text" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_toRightOf="@id/torrent_checkbox" |
||||||
|
android:textColor="#fff" |
||||||
|
android:textSize="15sp" |
||||||
|
android:text="CSI.Miami.Title-That_is_long.S13E16.HDTV.x264-LOL.mp4" |
||||||
|
android:textIsSelectable="true" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/ratio_text" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_below="@id/name_text" |
||||||
|
android:layout_alignParentRight="true" |
||||||
|
android:layout_marginLeft="@dimen/margin_half" |
||||||
|
android:layout_marginTop="4dip" |
||||||
|
android:text="UNKNOWN ETA" |
||||||
|
android:textSize="12sp" |
||||||
|
android:textIsSelectable="false" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/progress_text" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_alignBaseline="@id/ratio_text" |
||||||
|
android:layout_toLeftOf="@id/ratio_text" |
||||||
|
android:layout_toRightOf="@id/torrent_checkbox" |
||||||
|
android:text="325.6MB OF 388.8MB (0%)" |
||||||
|
android:textSize="12sp" |
||||||
|
android:textIsSelectable="false" /> |
||||||
|
|
||||||
|
<org.transdroid.lite.gui.TorrentProgressBar |
||||||
|
android:id="@+id/torrent_progressbar" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_below="@id/ratio_text" |
||||||
|
android:layout_marginTop="@dimen/margin_half" |
||||||
|
android:layout_marginBottom="@dimen/margin_half" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/speed_text" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_below="@id/torrent_progressbar" |
||||||
|
android:layout_alignParentRight="true" |
||||||
|
android:layout_marginLeft="@dimen/margin_half" |
||||||
|
android:text="↓400.8KB/s ↑1.4MB/s" |
||||||
|
android:textSize="12sp" |
||||||
|
android:textIsSelectable="false" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/peers_text" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_alignBaseline="@id/speed_text" |
||||||
|
android:layout_toLeftOf="@id/speed_text" |
||||||
|
android:layout_toRightOf="@id/torrent_checkbox" |
||||||
|
android:text="246 (288) LEECHERS" |
||||||
|
android:textSize="12sp" |
||||||
|
android:textIsSelectable="false" /> |
||||||
|
|
||||||
|
</fr.marvinlabs.widget.CheckableRelativeLayout> |
@ -0,0 +1,7 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<declare-styleable name="TorrentProgressBar"> |
||||||
|
<attr name="progress" format="integer" /> |
||||||
|
<attr name="isActive" format="boolean" /> |
||||||
|
</declare-styleable> |
||||||
|
</resources> |
@ -1,4 +1,5 @@ |
|||||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||||
<resources> |
<resources> |
||||||
<color name="green">#8acc12</color> |
<color name="green">#8acc12</color> |
||||||
|
<color name="ledgreen">#7dbb21</color> |
||||||
</resources> |
</resources> |
||||||
|
@ -0,0 +1,20 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > |
||||||
|
|
||||||
|
<CheckBoxPreference |
||||||
|
android:key="about_checkupdates" |
||||||
|
android:title="@string/pref_checkupdates" |
||||||
|
android:summary="@string/pref_checkupdates_info" |
||||||
|
android:defaultValue="true" /> |
||||||
|
|
||||||
|
<Preference |
||||||
|
android:key="about_sendlog" |
||||||
|
android:title="@string/pref_sendlog" |
||||||
|
android:summary="@string/pref_sendlog_info"> |
||||||
|
</Preference> |
||||||
|
|
||||||
|
<Preference |
||||||
|
android:key="about_about" |
||||||
|
android:title="@string/pref_about" /> |
||||||
|
|
||||||
|
</PreferenceScreen> |
@ -0,0 +1,52 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > |
||||||
|
|
||||||
|
<PreferenceCategory |
||||||
|
android:key="header_servers" |
||||||
|
android:title="@string/pref_servers" |
||||||
|
android:order="0"> |
||||||
|
<Preference |
||||||
|
android:key="header_addserver" |
||||||
|
android:title="@string/pref_addserver" |
||||||
|
android:order="99" /> |
||||||
|
</PreferenceCategory> |
||||||
|
|
||||||
|
<PreferenceCategory |
||||||
|
android:key="header_searchsites" |
||||||
|
android:title="@string/pref_servers" |
||||||
|
android:order="100"> |
||||||
|
<ListPreference |
||||||
|
android:key="header_setsearchsite" |
||||||
|
android:title="@string/pref_setsearchsite" |
||||||
|
android:order="101" /> |
||||||
|
<Preference |
||||||
|
android:key="header_addwebsearch" |
||||||
|
android:title="@string/pref_addwebsearch" |
||||||
|
android:order="199"/> |
||||||
|
</PreferenceCategory> |
||||||
|
|
||||||
|
<PreferenceCategory |
||||||
|
android:key="header_rssfeeds" |
||||||
|
android:title="@string/pref_rssfeeds" |
||||||
|
android:order="200"> |
||||||
|
<Preference |
||||||
|
android:key="header_addrssfeed" |
||||||
|
android:title="@string/pref_addrssfeed" |
||||||
|
android:order="199"/> |
||||||
|
</PreferenceCategory> |
||||||
|
|
||||||
|
<PreferenceCategory |
||||||
|
android:key="header_other" |
||||||
|
android:title="@string/pref_others" |
||||||
|
android:order="300"> |
||||||
|
<Preference |
||||||
|
android:key="header_background" |
||||||
|
android:title="@string/pref_background" |
||||||
|
android:order="301" /> |
||||||
|
<Preference |
||||||
|
android:key="header_system" |
||||||
|
android:title="@string/pref_system" |
||||||
|
android:order="302" /> |
||||||
|
</PreferenceCategory> |
||||||
|
|
||||||
|
</PreferenceScreen> |
@ -0,0 +1,47 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > |
||||||
|
|
||||||
|
<CheckBoxPreference |
||||||
|
android:key="notifications_enabled" |
||||||
|
android:title="@string/pref_notifications" |
||||||
|
android:summary="@string/pref_notifications_info" |
||||||
|
android:defaultValue="true" /> |
||||||
|
|
||||||
|
<ListPreference |
||||||
|
android:key="notifications_interval" |
||||||
|
android:title="@string/pref_notifyinterval" |
||||||
|
android:summary="@string/pref_notifyinterval_info" |
||||||
|
android:entries="@array/pref_notifyinterval_types" |
||||||
|
android:entryValues="@array/pref_notifyinterval_values" |
||||||
|
android:defaultValue="10800" |
||||||
|
android:dependency="notifications_enabled" /> |
||||||
|
|
||||||
|
<RingtonePreference |
||||||
|
android:key="notifications_sound" |
||||||
|
android:title="@string/pref_notifysound" |
||||||
|
android:ringtoneType="notification" |
||||||
|
android:showDefault="true" |
||||||
|
android:showSilent="true" |
||||||
|
android:dependency="notifications_enabled" /> |
||||||
|
|
||||||
|
<CheckBoxPreference |
||||||
|
android:key="notifications_vibrate" |
||||||
|
android:title="@string/pref_notifyvibrate" |
||||||
|
android:defaultValue="false" /> |
||||||
|
|
||||||
|
<net.margaritov.preference.colorpicker.ColorPickerPreference |
||||||
|
android:key="notifications_ledcolour" |
||||||
|
android:title="@string/pref_notifyled" |
||||||
|
android:summary="@string/pref_notifyled_info" |
||||||
|
android:defaultValue="@color/ledgreen" |
||||||
|
android:dependency="notifications_enabled" |
||||||
|
alphaSlider="false" /> |
||||||
|
|
||||||
|
<CheckBoxPreference |
||||||
|
android:key="notifications_adwnotify" |
||||||
|
android:title="@string/pref_notifyled" |
||||||
|
android:summary="@string/pref_notifyled_info" |
||||||
|
android:defaultValue="false" |
||||||
|
android:dependency="notifications_enabled" /> |
||||||
|
|
||||||
|
</PreferenceScreen> |
@ -0,0 +1,21 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > |
||||||
|
|
||||||
|
<EditTextPreference |
||||||
|
android:key="rssfeed_name" |
||||||
|
android:title="@string/pref_name" |
||||||
|
android:summary="@string/pref_name_optional" |
||||||
|
android:inputType="textNoSuggestions" /> |
||||||
|
|
||||||
|
<EditTextPreference |
||||||
|
android:key="rssfeed_url" |
||||||
|
android:title="@string/pref_feedurl" |
||||||
|
android:inputType="textUri" /> |
||||||
|
|
||||||
|
<CheckBoxPreference |
||||||
|
android:key="rssfeed_reqauth" |
||||||
|
android:title="@string/pref_reqauth" |
||||||
|
android:summary="@string/pref_reqauth_info" |
||||||
|
android:defaultValue="false" /> |
||||||
|
|
||||||
|
</PreferenceScreen> |
@ -0,0 +1,108 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > |
||||||
|
|
||||||
|
<EditTextPreference |
||||||
|
android:key="server_name" |
||||||
|
android:title="@string/pref_name" |
||||||
|
android:summary="@string/pref_name_optional" |
||||||
|
android:inputType="textNoSuggestions" /> |
||||||
|
<ListPreference |
||||||
|
android:key="server_type" |
||||||
|
android:title="@string/pref_servertype" |
||||||
|
android:entries="@array/pref_daemon_types" |
||||||
|
android:entryValues="@array/pref_daemon_values" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_address" |
||||||
|
android:title="@string/pref_address" |
||||||
|
android:summary="@string/pref_searchurl_info" |
||||||
|
android:inputType="textUri" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_port" |
||||||
|
android:title="@string/pref_address" |
||||||
|
android:summary="@string/pref_searchurl_info" |
||||||
|
android:inputType="numberSigned" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_user" |
||||||
|
android:title="@string/pref_user" |
||||||
|
android:inputType="textNoSuggestions" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_pass" |
||||||
|
android:title="@string/pref_pass" |
||||||
|
android:inputType="textPassword" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_extrapass" |
||||||
|
android:title="@string/pref_extrapass" |
||||||
|
android:inputType="textPassword" /> |
||||||
|
|
||||||
|
<PreferenceScreen android:title="@string/pref_advanced" > |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_localaddress" |
||||||
|
android:title="@string/pref_localaddress" |
||||||
|
android:summary="@string/pref_localaddress_info" |
||||||
|
android:inputType="textUri" /> |
||||||
|
<ListPreference |
||||||
|
android:key="server_localnetwork" |
||||||
|
android:title="@string/pref_localnetwork" |
||||||
|
android:summary="@string/pref_localnetwork_info" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_folder" |
||||||
|
android:title="@string/pref_folder" |
||||||
|
android:summary="@string/pref_folder_info" |
||||||
|
android:inputType="textUri" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_timeout" |
||||||
|
android:title="@string/pref_timeout" |
||||||
|
android:summary="@string/pref_timeout_info" |
||||||
|
android:inputType="numberSigned" /> |
||||||
|
<CheckBoxPreference |
||||||
|
android:key="server_sslenabled" |
||||||
|
android:title="@string/pref_sslenable" |
||||||
|
android:summary="@string/pref_sslenable_info" |
||||||
|
android:defaultValue="false" /> |
||||||
|
<CheckBoxPreference |
||||||
|
android:key="server_trustall" |
||||||
|
android:title="@string/pref_sslacceptall" |
||||||
|
android:summary="@string/pref_sslacceptall_info" |
||||||
|
android:defaultValue="false" |
||||||
|
android:dependency="server_sslenabled" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_ssltrustkey" |
||||||
|
android:title="@string/pref_sslkey" |
||||||
|
android:summary="@string/pref_sslkey_info" |
||||||
|
android:inputType="textNoSuggestions" |
||||||
|
android:dependency="server_sslenabled" /> |
||||||
|
</PreferenceScreen> |
||||||
|
|
||||||
|
<PreferenceScreen android:title="@string/pref_optional" > |
||||||
|
<CheckBoxPreference |
||||||
|
android:key="server_alarmfinished" |
||||||
|
android:title="@string/pref_alarmdone" |
||||||
|
android:summary="@string/pref_alarmdone_info" |
||||||
|
android:defaultValue="true" /> |
||||||
|
<CheckBoxPreference |
||||||
|
android:key="server_alarmnew" |
||||||
|
android:title="@string/pref_alarmnew" |
||||||
|
android:summary="@string/pref_alarmnew_info" |
||||||
|
android:defaultValue="false" /> |
||||||
|
<ListPreference |
||||||
|
android:key="server_os" |
||||||
|
android:title="@string/pref_os" |
||||||
|
android:entries="@array/pref_os_types" |
||||||
|
android:entryValues="@array/pref_os_values" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_downloaddir" |
||||||
|
android:title="@string/pref_downdir" |
||||||
|
android:summary="@string/pref_downdir_info" |
||||||
|
android:inputType="textUri" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_ftpurl" |
||||||
|
android:title="@string/pref_ftpurl" |
||||||
|
android:summary="@string/pref_ftpurl_into" |
||||||
|
android:inputType="textUri" /> |
||||||
|
<EditTextPreference |
||||||
|
android:key="server_ftppass" |
||||||
|
android:title="@string/pref_ftppass" |
||||||
|
android:inputType="textPassword" /> |
||||||
|
</PreferenceScreen> |
||||||
|
|
||||||
|
</PreferenceScreen> |
@ -0,0 +1,16 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > |
||||||
|
|
||||||
|
<EditTextPreference |
||||||
|
android:key="websearch_name" |
||||||
|
android:title="@string/pref_name" |
||||||
|
android:summary="@string/pref_name_optional" |
||||||
|
android:inputType="textNoSuggestions" /> |
||||||
|
|
||||||
|
<EditTextPreference |
||||||
|
android:key="websearch_url" |
||||||
|
android:title="@string/pref_searchurl" |
||||||
|
android:summary="@string/pref_searchurl_info" |
||||||
|
android:inputType="textUri" /> |
||||||
|
|
||||||
|
</PreferenceScreen> |
@ -0,0 +1,337 @@ |
|||||||
|
package com.actionbarsherlock.view; |
||||||
|
|
||||||
|
import android.annotation.TargetApi; |
||||||
|
import android.content.Context; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.util.SparseBooleanArray; |
||||||
|
import android.view.View; |
||||||
|
import android.widget.AdapterView; |
||||||
|
import android.widget.Checkable; |
||||||
|
import android.widget.ListView; |
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockActivity; |
||||||
|
import com.actionbarsherlock.app.SherlockFragmentActivity; |
||||||
|
import com.actionbarsherlock.view.ActionMode; |
||||||
|
import com.actionbarsherlock.view.Menu; |
||||||
|
import com.actionbarsherlock.view.MenuItem; |
||||||
|
|
||||||
|
/** |
||||||
|
* Provides backwards compatible multiple choice ActionMode support on Froyo+ using ActionBarSherlock. |
||||||
|
*/ |
||||||
|
public class SherlockListView extends ListView { |
||||||
|
// API 11+ reference, but ok because the value will be inlined.
|
||||||
|
public static final int CHOICE_MODE_MULTIPLE_MODAL_COMPAT = CHOICE_MODE_MULTIPLE_MODAL; |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper to intercept delegation of long click events, and pass to {@link #doLongPress} |
||||||
|
*/ |
||||||
|
class OnItemLongClickListenerWrapper implements OnItemLongClickListener { |
||||||
|
private OnItemLongClickListener wrapped; |
||||||
|
|
||||||
|
public void setWrapped(OnItemLongClickListener listener) { |
||||||
|
this.wrapped = listener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onItemLongClick(AdapterView<?> view, View child, int position, long id) { |
||||||
|
// this would be easier if AbsListView.performLongPress wasn't package
|
||||||
|
// protected :-(
|
||||||
|
boolean handled = doLongPress(child, position, id); |
||||||
|
if (!handled && wrapped != null) { |
||||||
|
return wrapped.onItemLongClick(view, child, position, id); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Hijack the onLongClickListener so we can intercept delegation. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void setOnItemLongClickListener(OnItemLongClickListener listener) { |
||||||
|
if (longClickListenerWrapper == null) { |
||||||
|
longClickListenerWrapper = new OnItemLongClickListenerWrapper(); |
||||||
|
} |
||||||
|
longClickListenerWrapper.setWrapped(listener); |
||||||
|
super.setOnItemLongClickListener(longClickListenerWrapper); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* A MultiChoiceModeListener receives events for {@link AbsListView#CHOICE_MODE_MULTIPLE_MODAL}. It acts as the |
||||||
|
* {@link ActionMode.Callback} for the selection mode and also receives |
||||||
|
* {@link #onItemCheckedStateChanged(ActionMode, int, long, boolean)} events when the user selects and deselects |
||||||
|
* list items. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("javadoc") |
||||||
|
public interface MultiChoiceModeListenerCompat extends ActionMode.Callback { |
||||||
|
/** |
||||||
|
* Called when an item is checked or unchecked during selection mode. |
||||||
|
* @param mode The {@link ActionMode} providing the selection mode |
||||||
|
* @param position Adapter position of the item that was checked or unchecked |
||||||
|
* @param id Adapter ID of the item that was checked or unchecked |
||||||
|
* @param checked <code>true</code> if the item is now checked, <code>false</code> if the item is now unchecked. |
||||||
|
*/ |
||||||
|
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked); |
||||||
|
} |
||||||
|
|
||||||
|
class MultiChoiceModeWrapper implements MultiChoiceModeListenerCompat { |
||||||
|
private MultiChoiceModeListenerCompat wrapped; |
||||||
|
|
||||||
|
public void setWrapped(MultiChoiceModeListenerCompat wrapped) { |
||||||
|
this.wrapped = wrapped; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) { |
||||||
|
if (wrapped == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if (wrapped.onCreateActionMode(mode, menu)) { |
||||||
|
// Initialize checked graphic state?
|
||||||
|
setLongClickable(false); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu) { |
||||||
|
if (wrapped == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return wrapped.onPrepareActionMode(mode, menu); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onActionItemClicked(ActionMode mode, MenuItem item) { |
||||||
|
if (wrapped == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return wrapped.onActionItemClicked(mode, item); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onDestroyActionMode(ActionMode mode) { |
||||||
|
if (wrapped == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
wrapped.onDestroyActionMode(mode); |
||||||
|
actionMode = null; |
||||||
|
|
||||||
|
// Ending selection mode means deselecting everything.
|
||||||
|
clearChoices(); |
||||||
|
checkedItemCount = 0; |
||||||
|
updateOnScreenCheckedViews(); |
||||||
|
invalidateViews(); |
||||||
|
setLongClickable(true); |
||||||
|
requestLayout(); |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { |
||||||
|
if (wrapped == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
wrapped.onItemCheckedStateChanged(mode, position, id, checked); |
||||||
|
|
||||||
|
// If there are no items selected we no longer need the selection mode.
|
||||||
|
if (checkedItemCount == 0) { |
||||||
|
mode.finish(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private com.actionbarsherlock.view.ActionMode actionMode; |
||||||
|
private OnItemLongClickListenerWrapper longClickListenerWrapper; |
||||||
|
private MultiChoiceModeWrapper choiceModeListener; |
||||||
|
private int choiceMode; |
||||||
|
private int checkedItemCount; |
||||||
|
|
||||||
|
public SherlockListView(Context context) { |
||||||
|
super(context); |
||||||
|
init(context); |
||||||
|
} |
||||||
|
|
||||||
|
public SherlockListView(Context context, AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
init(context); |
||||||
|
} |
||||||
|
|
||||||
|
public SherlockListView(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
init(context); |
||||||
|
} |
||||||
|
|
||||||
|
void init(Context context) { |
||||||
|
if (isInEditMode()) { |
||||||
|
// Ignore when viewing in the UI designer
|
||||||
|
return; |
||||||
|
} |
||||||
|
if (!(context instanceof SherlockActivity || context instanceof SherlockFragmentActivity)) { |
||||||
|
throw new IllegalStateException( |
||||||
|
"This view must be hosted in a SherlockActivity or SherlockFragmentActivity"); |
||||||
|
} |
||||||
|
setOnItemLongClickListener(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setChoiceMode(int mode) { |
||||||
|
choiceMode = mode; |
||||||
|
if (actionMode != null) { |
||||||
|
actionMode.finish(); |
||||||
|
actionMode = null; |
||||||
|
} |
||||||
|
if (choiceMode != CHOICE_MODE_NONE) { |
||||||
|
if (mode == CHOICE_MODE_MULTIPLE_MODAL_COMPAT) { |
||||||
|
clearChoices(); |
||||||
|
checkedItemCount = 0; |
||||||
|
setLongClickable(true); |
||||||
|
updateOnScreenCheckedViews(); |
||||||
|
requestLayout(); |
||||||
|
invalidate(); |
||||||
|
mode = CHOICE_MODE_MULTIPLE; |
||||||
|
} |
||||||
|
super.setChoiceMode(mode); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getChoiceMode() { |
||||||
|
return choiceMode; |
||||||
|
} |
||||||
|
|
||||||
|
public void setMultiChoiceModeListener(MultiChoiceModeListenerCompat listener) { |
||||||
|
if (choiceModeListener == null) { |
||||||
|
choiceModeListener = new MultiChoiceModeWrapper(); |
||||||
|
} |
||||||
|
choiceModeListener.setWrapped(listener); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean performItemClick(View view, int position, long id) { |
||||||
|
boolean handled = false; |
||||||
|
boolean dispatchItemClick = true; |
||||||
|
boolean checkStateChanged = false; |
||||||
|
if (choiceMode != CHOICE_MODE_NONE) { |
||||||
|
handled = true; |
||||||
|
if (choiceMode == CHOICE_MODE_MULTIPLE |
||||||
|
|| (choiceMode == CHOICE_MODE_MULTIPLE_MODAL_COMPAT && actionMode != null)) { |
||||||
|
boolean newValue = !getCheckedItemPositions().get(position); |
||||||
|
setItemChecked(position, newValue); |
||||||
|
if (actionMode != null) { |
||||||
|
choiceModeListener.onItemCheckedStateChanged(actionMode, position, id, newValue); |
||||||
|
dispatchItemClick = false; |
||||||
|
} |
||||||
|
checkStateChanged = true; |
||||||
|
return false; |
||||||
|
} else if (choiceMode == CHOICE_MODE_SINGLE) { |
||||||
|
boolean newValue = !getCheckedItemPositions().get(position); |
||||||
|
setItemChecked(position, newValue); |
||||||
|
checkStateChanged = true; |
||||||
|
} |
||||||
|
if (checkStateChanged) { |
||||||
|
updateOnScreenCheckedViews(); |
||||||
|
} |
||||||
|
} |
||||||
|
if (dispatchItemClick) { |
||||||
|
handled |= super.performItemClick(view, position, id); |
||||||
|
} |
||||||
|
return handled; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Perform a quick, in-place update of the checked or activated state on all visible item views. This should only be |
||||||
|
* called when a valid choice mode is active. |
||||||
|
* <p> |
||||||
|
* (Taken verbatim from AbsListView.java) |
||||||
|
*/ |
||||||
|
@TargetApi(11) |
||||||
|
private void updateOnScreenCheckedViews() { |
||||||
|
final int firstPos = getFirstVisiblePosition(); |
||||||
|
final int count = getChildCount(); |
||||||
|
final boolean useActivated = getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB; |
||||||
|
for (int i = 0; i < count; i++) { |
||||||
|
final View child = getChildAt(i); |
||||||
|
final int position = firstPos + i; |
||||||
|
|
||||||
|
if (child instanceof Checkable) { |
||||||
|
((Checkable) child).setChecked(getCheckedItemPositions().get(position)); |
||||||
|
} else if (useActivated) { |
||||||
|
child.setActivated(getCheckedItemPositions().get(position)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public ActionMode startActionMode(ActionMode.Callback callback) { |
||||||
|
if (actionMode != null) { |
||||||
|
return actionMode; |
||||||
|
} |
||||||
|
Context context = getContext(); |
||||||
|
if (context instanceof SherlockActivity) { |
||||||
|
actionMode = ((SherlockActivity) getContext()).startActionMode(callback); |
||||||
|
} else if (context instanceof SherlockFragmentActivity) { |
||||||
|
actionMode = ((SherlockFragmentActivity) context).startActionMode(callback); |
||||||
|
} else { |
||||||
|
throw new IllegalStateException( |
||||||
|
"This view must be hosted in a SherlockActivity or SherlockFragmentActivity"); |
||||||
|
} |
||||||
|
return actionMode; |
||||||
|
} |
||||||
|
|
||||||
|
boolean doLongPress(final View child, final int longPressPosition, final long longPressId) { |
||||||
|
if (choiceMode == CHOICE_MODE_MULTIPLE_MODAL_COMPAT) { |
||||||
|
if (actionMode == null && (actionMode = startActionMode(choiceModeListener)) != null) { |
||||||
|
setItemChecked(longPressPosition, true); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the checked state of the specified position. The is only valid if the choice mode has been set to |
||||||
|
* {@link #CHOICE_MODE_SINGLE} or {@link #CHOICE_MODE_MULTIPLE}. |
||||||
|
* @param position The item whose checked state is to be checked |
||||||
|
* @param value The new checked state for the item |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void setItemChecked(int position, boolean value) { |
||||||
|
if (choiceMode == CHOICE_MODE_NONE) { |
||||||
|
return; |
||||||
|
} |
||||||
|
SparseBooleanArray checkStates = getCheckedItemPositions(); |
||||||
|
|
||||||
|
// Start selection mode if needed. We don't need to if we're unchecking
|
||||||
|
// something.
|
||||||
|
if (value && choiceMode == CHOICE_MODE_MULTIPLE_MODAL_COMPAT && actionMode == null) { |
||||||
|
actionMode = startActionMode(choiceModeListener); |
||||||
|
} |
||||||
|
|
||||||
|
if (choiceMode == CHOICE_MODE_MULTIPLE || choiceMode == CHOICE_MODE_MULTIPLE_MODAL) { |
||||||
|
// boolean oldValue = checkStates.get(position);
|
||||||
|
checkStates.put(position, value); |
||||||
|
if (value) { |
||||||
|
checkedItemCount++; |
||||||
|
} else { |
||||||
|
checkedItemCount--; |
||||||
|
} |
||||||
|
if (actionMode != null) { |
||||||
|
final long id = getAdapter().getItemId(position); |
||||||
|
choiceModeListener.onItemCheckedStateChanged(actionMode, position, id, value); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (value || isItemChecked(position)) { |
||||||
|
checkStates.clear(); |
||||||
|
} |
||||||
|
// this may end up selecting the value we just cleared but this way
|
||||||
|
// we ensure length of checkStates is 1, a fact getCheckedItemPosition
|
||||||
|
// relies on
|
||||||
|
if (value) { |
||||||
|
checkStates.put(position, true); |
||||||
|
} |
||||||
|
} |
||||||
|
requestLayout(); |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,100 @@ |
|||||||
|
package fr.marvinlabs.widget; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
import android.widget.Checkable; |
||||||
|
import android.widget.RelativeLayout; |
||||||
|
|
||||||
|
/** |
||||||
|
* Extension of a relative layout to provide a checkable behaviour |
||||||
|
* |
||||||
|
* @author marvinlabs |
||||||
|
*/ |
||||||
|
public class CheckableRelativeLayout extends RelativeLayout implements Checkable { |
||||||
|
|
||||||
|
private boolean isChecked; |
||||||
|
private List<Checkable> checkableViews; |
||||||
|
|
||||||
|
public CheckableRelativeLayout(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
initialise(attrs); |
||||||
|
} |
||||||
|
|
||||||
|
public CheckableRelativeLayout(Context context, AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
initialise(attrs); |
||||||
|
} |
||||||
|
|
||||||
|
public CheckableRelativeLayout(Context context, int checkableId) { |
||||||
|
super(context); |
||||||
|
initialise(null); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* @see android.widget.Checkable#isChecked() |
||||||
|
*/ |
||||||
|
public boolean isChecked() { |
||||||
|
return isChecked; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* @see android.widget.Checkable#setChecked(boolean) |
||||||
|
*/ |
||||||
|
public void setChecked(boolean isChecked) { |
||||||
|
this.isChecked = isChecked; |
||||||
|
for (Checkable c : checkableViews) { |
||||||
|
c.setChecked(isChecked); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* @see android.widget.Checkable#toggle() |
||||||
|
*/ |
||||||
|
public void toggle() { |
||||||
|
this.isChecked = !this.isChecked; |
||||||
|
for (Checkable c : checkableViews) { |
||||||
|
c.toggle(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onFinishInflate() { |
||||||
|
super.onFinishInflate(); |
||||||
|
|
||||||
|
final int childCount = this.getChildCount(); |
||||||
|
for (int i = 0; i < childCount; ++i) { |
||||||
|
findCheckableChildren(this.getChildAt(i)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Read the custom XML attributes |
||||||
|
*/ |
||||||
|
private void initialise(AttributeSet attrs) { |
||||||
|
this.isChecked = false; |
||||||
|
this.checkableViews = new ArrayList<Checkable>(5); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add to our checkable list all the children of the view that implement the |
||||||
|
* interface Checkable |
||||||
|
*/ |
||||||
|
private void findCheckableChildren(View v) { |
||||||
|
if (v instanceof Checkable) { |
||||||
|
this.checkableViews.add((Checkable) v); |
||||||
|
} |
||||||
|
|
||||||
|
if (v instanceof ViewGroup) { |
||||||
|
final ViewGroup vg = (ViewGroup) v; |
||||||
|
final int childCount = vg.getChildCount(); |
||||||
|
for (int i = 0; i < childCount; ++i) { |
||||||
|
findCheckableChildren(vg.getChildAt(i)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
package fr.marvinlabs.widget; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.KeyEvent; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.widget.CheckBox; |
||||||
|
|
||||||
|
/** |
||||||
|
* CheckBox that does not react to any user event in order to let the container handle them. |
||||||
|
*/ |
||||||
|
public class InertCheckBox extends CheckBox { |
||||||
|
|
||||||
|
// Provide the same constructors as the superclass
|
||||||
|
public InertCheckBox(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
} |
||||||
|
|
||||||
|
// Provide the same constructors as the superclass
|
||||||
|
public InertCheckBox(Context context, AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
} |
||||||
|
|
||||||
|
// Provide the same constructors as the superclass
|
||||||
|
public InertCheckBox(Context context) { |
||||||
|
super(context); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onTouchEvent(MotionEvent event) { |
||||||
|
// Make the checkbox not respond to any user event
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onKeyDown(int keyCode, KeyEvent event) { |
||||||
|
// Make the checkbox not respond to any user event
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { |
||||||
|
// Make the checkbox not respond to any user event
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onKeyPreIme(int keyCode, KeyEvent event) { |
||||||
|
// Make the checkbox not respond to any user event
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onKeyShortcut(int keyCode, KeyEvent event) { |
||||||
|
// Make the checkbox not respond to any user event
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onKeyUp(int keyCode, KeyEvent event) { |
||||||
|
// Make the checkbox not respond to any user event
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onTrackballEvent(MotionEvent event) { |
||||||
|
// Make the checkbox not respond to any user event
|
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,109 @@ |
|||||||
|
package org.transdroid.lite.app.search; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.EBean; |
||||||
|
import org.androidannotations.annotations.EBean.Scope; |
||||||
|
import org.androidannotations.annotations.RootContext; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.database.Cursor; |
||||||
|
import android.net.Uri; |
||||||
|
|
||||||
|
@EBean(scope = Scope.Singleton) |
||||||
|
public class SearchHelper { |
||||||
|
|
||||||
|
static final int CURSOR_SEARCH_ID = 0; |
||||||
|
static final int CURSOR_SEARCH_NAME = 1; |
||||||
|
static final int CURSOR_SEARCH_TORRENTURL = 2; |
||||||
|
static final int CURSOR_SEARCH_DETAILSURL = 3; |
||||||
|
static final int CURSOR_SEARCH_SIZE = 4; |
||||||
|
static final int CURSOR_SEARCH_ADDED = 5; |
||||||
|
static final int CURSOR_SEARCH_SEEDERS = 6; |
||||||
|
static final int CURSOR_SEARCH_LEECHERS = 7; |
||||||
|
|
||||||
|
static final int CURSOR_SITE_ID = 0; |
||||||
|
static final int CURSOR_SITE_CODE = 1; |
||||||
|
static final int CURSOR_SITE_NAME = 2; |
||||||
|
static final int CURSOR_SITE_RSSURL = 3; |
||||||
|
|
||||||
|
@RootContext |
||||||
|
protected Context context; |
||||||
|
|
||||||
|
public enum SearchSortOrder { |
||||||
|
Combined, BySeeders |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return whether the Torrent Search package is installed and available to query against |
||||||
|
* @return True if the available sites can be retrieved from the content provider, false otherwise |
||||||
|
*/ |
||||||
|
public boolean isTorrentSearchInstalled() { |
||||||
|
return getAvailableSites() != null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Queries the Torrent Search package for all available in-app search sites. This method is synchronous. |
||||||
|
* @return A list of available search sites as POJOs, or null if the Torrent Search package is not installed |
||||||
|
*/ |
||||||
|
public List<SearchSite> getAvailableSites() { |
||||||
|
|
||||||
|
// Try to access the TorrentSitesProvider to retrieve all available in-app torrent search sites
|
||||||
|
Uri uri = Uri.parse("content://org.transdroid.search.torrentsitesprovider/sites"); |
||||||
|
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); |
||||||
|
if (cursor.moveToFirst()) { |
||||||
|
List<SearchSite> sites = new ArrayList<SearchSite>(); |
||||||
|
do { |
||||||
|
// Read the cursor fields into the SearchSite object
|
||||||
|
sites.add(new SearchSite(cursor.getInt(CURSOR_SITE_ID), cursor.getString(CURSOR_SITE_CODE), cursor |
||||||
|
.getString(CURSOR_SITE_NAME), cursor.getString(CURSOR_SITE_RSSURL))); |
||||||
|
} while (cursor.moveToNext()); |
||||||
|
cursor.close(); |
||||||
|
return sites; |
||||||
|
} |
||||||
|
|
||||||
|
// Torrent Search package is not yet installed
|
||||||
|
return null; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Queries the Torrent Search module to search for torrents on the web. This method is synchornous and should always |
||||||
|
* be called in a background thread. |
||||||
|
* @param query The search query to pass to the torrent site |
||||||
|
* @param site The site to search, as retrieved from the TorrentSitesProvider, or null if the Torrent Search package |
||||||
|
* @param sortBy.name() The sort order to request from the torrent site, if supported |
||||||
|
* @return A list of torrent search results as POJOs, or null if the Torrent Search package is not installed |
||||||
|
*/ |
||||||
|
public List<SearchResult> search(String query, SearchSite site, SearchSortOrder sortBy) { |
||||||
|
|
||||||
|
// Try to query the TorrentSearchProvider to search for torrents on the web
|
||||||
|
Uri uri = Uri.parse("content://org.transdroid.search.torrentsearchprovider/search/" + query); |
||||||
|
Cursor cursor; |
||||||
|
if (site == null) { |
||||||
|
// If no explicit site was supplied, rely on the Torrent Search package's default
|
||||||
|
cursor = context.getContentResolver().query(uri, null, null, null, sortBy.name()); |
||||||
|
} else { |
||||||
|
cursor = context.getContentResolver().query(uri, null, "SITE = ?", new String[] { site.getKey() }, |
||||||
|
sortBy.name()); |
||||||
|
} |
||||||
|
if (cursor.moveToFirst()) { |
||||||
|
List<SearchResult> results = new ArrayList<SearchResult>(); |
||||||
|
do { |
||||||
|
// Read the cursor fields into the SearchResult object
|
||||||
|
results.add(new SearchResult(cursor.getInt(CURSOR_SEARCH_ID), cursor.getString(CURSOR_SEARCH_NAME), |
||||||
|
cursor.getString(CURSOR_SEARCH_TORRENTURL), cursor.getString(CURSOR_SEARCH_DETAILSURL), cursor |
||||||
|
.getString(CURSOR_SEARCH_SIZE), cursor.getLong(CURSOR_SEARCH_ADDED), cursor |
||||||
|
.getString(CURSOR_SEARCH_SEEDERS), cursor.getString(CURSOR_SEARCH_LEECHERS))); |
||||||
|
} while (cursor.moveToNext()); |
||||||
|
cursor.close(); |
||||||
|
return results; |
||||||
|
} |
||||||
|
|
||||||
|
// Torrent Search package is not yet installed
|
||||||
|
return null; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
package org.transdroid.lite.app.search; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents a search result as retrieved by querying the Torrent Search package. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class SearchResult { |
||||||
|
|
||||||
|
private final int id; |
||||||
|
private final String name; |
||||||
|
private final String torrentUrl; |
||||||
|
private final String detailsUrl; |
||||||
|
private final String size; |
||||||
|
private final Date addedOn; |
||||||
|
private final String seeders; |
||||||
|
private final String leechers; |
||||||
|
|
||||||
|
public SearchResult(int id, String name, String torrentUrl, String detailsUrl, String size, long addedOnTime, |
||||||
|
String seeders, String leechers) { |
||||||
|
this.id = id; |
||||||
|
this.name = name; |
||||||
|
this.torrentUrl = torrentUrl; |
||||||
|
this.detailsUrl = detailsUrl; |
||||||
|
this.size = size; |
||||||
|
this.addedOn = (addedOnTime == -1L) ? null : new Date(addedOnTime); |
||||||
|
this.seeders = seeders; |
||||||
|
this.leechers = leechers; |
||||||
|
} |
||||||
|
|
||||||
|
public int getId() { |
||||||
|
return id; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
public String getTorrentUrl() { |
||||||
|
return torrentUrl; |
||||||
|
} |
||||||
|
|
||||||
|
public String getDetailsUrl() { |
||||||
|
return detailsUrl; |
||||||
|
} |
||||||
|
|
||||||
|
public String getSize() { |
||||||
|
return size; |
||||||
|
} |
||||||
|
|
||||||
|
public Date getAddedOn() { |
||||||
|
return addedOn; |
||||||
|
} |
||||||
|
|
||||||
|
public String getSeeders() { |
||||||
|
return seeders; |
||||||
|
} |
||||||
|
|
||||||
|
public String getLeechers() { |
||||||
|
return leechers; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package org.transdroid.lite.app.search; |
||||||
|
|
||||||
|
import org.transdroid.lite.gui.navigation.FilterItem; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents an available torrent site that can be searched using the Torrent Search package. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class SearchSite implements FilterItem { |
||||||
|
|
||||||
|
private final int id; |
||||||
|
private final String key; |
||||||
|
private final String name; |
||||||
|
private final String rssFeedUrl; |
||||||
|
|
||||||
|
public SearchSite(int id, String key, String name, String rssFeedUrl) { |
||||||
|
this.id = id; |
||||||
|
this.key = key; |
||||||
|
this.name = name; |
||||||
|
this.rssFeedUrl = rssFeedUrl; |
||||||
|
} |
||||||
|
|
||||||
|
public int getId() { |
||||||
|
return id; |
||||||
|
} |
||||||
|
|
||||||
|
public String getKey() { |
||||||
|
return key; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
public String getRssFeedUrl() { |
||||||
|
return rssFeedUrl; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
package org.transdroid.lite.app.settings; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.EBean; |
||||||
|
import org.androidannotations.annotations.RootContext; |
||||||
|
import org.androidannotations.annotations.EBean.Scope; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.SharedPreferences; |
||||||
|
import android.preference.PreferenceManager; |
||||||
|
|
||||||
|
/** |
||||||
|
* Allows instantiation of the settings specified in R.xml.pref_about. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EBean(scope = Scope.Singleton) |
||||||
|
public class AboutSettings { |
||||||
|
|
||||||
|
@RootContext |
||||||
|
protected Context context; |
||||||
|
private SharedPreferences prefs; |
||||||
|
|
||||||
|
protected AboutSettings(Context context) { |
||||||
|
prefs = PreferenceManager.getDefaultSharedPreferences(context); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean checkForUpdates() { |
||||||
|
return prefs.getBoolean("about_checkupdates", true); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,140 @@ |
|||||||
|
package org.transdroid.lite.app.settings; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.EBean; |
||||||
|
import org.androidannotations.annotations.EBean.Scope; |
||||||
|
import org.androidannotations.annotations.RootContext; |
||||||
|
import org.transdroid.daemon.Daemon; |
||||||
|
import org.transdroid.daemon.OS; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.SharedPreferences; |
||||||
|
import android.preference.PreferenceManager; |
||||||
|
|
||||||
|
/** |
||||||
|
* Singleton object to access all application settings, including stored servers, web search sites and RSS feeds. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EBean(scope = Scope.Singleton) |
||||||
|
public class ApplicationSettings { |
||||||
|
|
||||||
|
@RootContext |
||||||
|
protected Context context; |
||||||
|
private SharedPreferences prefs; |
||||||
|
|
||||||
|
protected ApplicationSettings(Context context) { |
||||||
|
prefs = PreferenceManager.getDefaultSharedPreferences(context); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all available user-configured servers |
||||||
|
* @return A list of all stored server settings objects |
||||||
|
*/ |
||||||
|
public List<ServerSetting> getServerSettings() { |
||||||
|
List<ServerSetting> servers = new ArrayList<ServerSetting>(); |
||||||
|
for (int i = 0; i <= getMaxServer(); i++) { |
||||||
|
servers.add(getServerSetting(i)); |
||||||
|
} |
||||||
|
return servers; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the order number/identifying key of the last server |
||||||
|
* @return The zero-based order number (index) of the last stored server settings |
||||||
|
*/ |
||||||
|
public int getMaxServer() { |
||||||
|
for (int i = 0; true; i++) { |
||||||
|
if (prefs.getString("server_type_" + i, null) == null) |
||||||
|
return i - 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the user-specified server settings for a specific server |
||||||
|
* @param order The order number/identifying key of the settings to retrieve |
||||||
|
* @return The server settings object, loaded from shared preferences |
||||||
|
*/ |
||||||
|
public ServerSetting getServerSetting(int order) { |
||||||
|
return new ServerSetting(order, prefs.getString("server_name_" + order, null), Daemon.fromCode(prefs.getString( |
||||||
|
"server_type_" + order, null)), prefs.getString("server_address_" + order, null), prefs.getString( |
||||||
|
"server_localaddress_" + order, null), prefs.getString("server_localnetwork_" + order, null), |
||||||
|
prefs.getInt("server_port_" + order, -1), prefs.getBoolean("server_sslenabled_" + order, false), |
||||||
|
prefs.getBoolean("server_ssltrustall_" + order, false), prefs.getString("server_ssltrustkey_" + order, |
||||||
|
null), prefs.getString("server_folder_" + order, null), prefs.getBoolean("server_useauth_" |
||||||
|
+ order, true), prefs.getString("server_user_" + order, null), prefs.getString("server_pass_" |
||||||
|
+ order, null), prefs.getString("server_extrapass_" + order, null), OS.fromCode(prefs |
||||||
|
.getString("server_os_" + order, null)), prefs.getString("server_downloaddir_" + order, null), |
||||||
|
prefs.getString("server_ftpurl_" + order, null), prefs.getString("server_ftppass_" + order, null), |
||||||
|
prefs.getInt("server_timeout_" + order, -1), prefs.getBoolean("server_alarmfinished_" + order, true), |
||||||
|
prefs.getBoolean("server_alarmnew_" + order, false), false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all available user-configured web-based (as opped to in-app) search sites |
||||||
|
* @return A list of all stored web search site settings objects |
||||||
|
*/ |
||||||
|
public List<WebsearchSetting> getWebsearchSettings() { |
||||||
|
List<WebsearchSetting> websearches = new ArrayList<WebsearchSetting>(); |
||||||
|
for (int i = 0; i <= getMaxWebsearch(); i++) { |
||||||
|
websearches.add(getWebsearchSetting(i)); |
||||||
|
} |
||||||
|
return websearches; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the order number/identifying key of the last web search site |
||||||
|
* @return The zero-based order number (index) of the last stored web search site |
||||||
|
*/ |
||||||
|
public int getMaxWebsearch() { |
||||||
|
for (int i = 0; true; i++) { |
||||||
|
if (prefs.getString("websearch_url_" + i, null) == null) |
||||||
|
return i - 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the user-specified web-based search site setting for a specific site |
||||||
|
* @param order The order number/identifying key of the settings to retrieve |
||||||
|
* @return The web search site settings object, loaded from shared preferences |
||||||
|
*/ |
||||||
|
public WebsearchSetting getWebsearchSetting(int order) { |
||||||
|
return new WebsearchSetting(order, prefs.getString("websearch_name_" + order, null), prefs.getString( |
||||||
|
"websearch_url_" + order, null)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all available user-configured RSS feeds |
||||||
|
* @return A list of all stored RSS feed settings objects |
||||||
|
*/ |
||||||
|
public List<RssfeedSetting> getRssfeedSettings() { |
||||||
|
List<RssfeedSetting> rssfeeds = new ArrayList<RssfeedSetting>(); |
||||||
|
for (int i = 0; i <= getMaxRssfeed(); i++) { |
||||||
|
rssfeeds.add(getRssfeedSetting(i)); |
||||||
|
} |
||||||
|
return rssfeeds; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the order number/identifying key of the last stored RSS feed |
||||||
|
* @return The zero-based order number (index) of the last stored RSS feed |
||||||
|
*/ |
||||||
|
public int getMaxRssfeed() { |
||||||
|
for (int i = 0; true; i++) { |
||||||
|
if (prefs.getString("rssfeed_feedurl_" + i, null) == null) |
||||||
|
return i - 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the user-specified RSS feed setting for a specific feed |
||||||
|
* @param order The order number/identifying key of the settings to retrieve |
||||||
|
* @return The RSS feed settings object, loaded from shared preferences |
||||||
|
*/ |
||||||
|
public RssfeedSetting getRssfeedSetting(int order) { |
||||||
|
return new RssfeedSetting(order, prefs.getString("rssfeed_name_" + order, null), prefs.getString( |
||||||
|
"rssfeed_feedurl_" + order, null), prefs.getBoolean("rssfeed_reqauth_" + order, false)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
package org.transdroid.lite.app.settings; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.EBean; |
||||||
|
import org.androidannotations.annotations.EBean.Scope; |
||||||
|
import org.androidannotations.annotations.RootContext; |
||||||
|
import org.transdroid.core.R; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.SharedPreferences; |
||||||
|
import android.net.Uri; |
||||||
|
import android.preference.PreferenceManager; |
||||||
|
import android.provider.Settings; |
||||||
|
|
||||||
|
/** |
||||||
|
* Allows instantiation of the settings specified in R.xml.pref_notifications. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EBean(scope = Scope.Singleton) |
||||||
|
public class NotificationSettings { |
||||||
|
|
||||||
|
@RootContext |
||||||
|
protected Context context; |
||||||
|
private SharedPreferences prefs; |
||||||
|
|
||||||
|
protected NotificationSettings(Context context) { |
||||||
|
prefs = PreferenceManager.getDefaultSharedPreferences(context); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether the background service is enabled, i.e. whether the user want to receive notifications |
||||||
|
* @return True if the server should be checked for torrent status updates |
||||||
|
*/ |
||||||
|
public boolean isEnabled() { |
||||||
|
return prefs.getBoolean("notifications_enabled", true); |
||||||
|
} |
||||||
|
|
||||||
|
private String getRawInverval() { |
||||||
|
return prefs.getString("notifications_interval", "10800"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the interval between two server checks |
||||||
|
* @return The interval, in milliseconds |
||||||
|
*/ |
||||||
|
public Long getInvervalInMilliseconds() { |
||||||
|
return Long.parseLong(getRawInverval()) * 1000L; |
||||||
|
} |
||||||
|
|
||||||
|
private String getRawSound() { |
||||||
|
return prefs.getString("notifications_sound", null); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the sound (ring tone) to play on a new notification, or null if it should not play any |
||||||
|
* @return Either the user-specified sound, null if the user specified 'Silent' or the system default notification sound |
||||||
|
*/ |
||||||
|
public Uri getSound() { |
||||||
|
String raw = getRawSound(); |
||||||
|
if (raw == null) |
||||||
|
return null; |
||||||
|
if (raw.equals("")) |
||||||
|
return Settings.System.DEFAULT_NOTIFICATION_URI; |
||||||
|
return Uri.parse(raw); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether the device should vibrate on a new notification |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public boolean shouldVibrate() { |
||||||
|
return prefs.getBoolean("notifications_vibrate", false); |
||||||
|
} |
||||||
|
|
||||||
|
private int getRawLedColour() { |
||||||
|
return prefs.getInt("notifications_ledcolour", -1); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the LED colour to use on a new notification |
||||||
|
* @return The integer value of the user-specified or default colour |
||||||
|
*/ |
||||||
|
public int getDesiredLedColour() { |
||||||
|
int raw = getRawLedColour(); |
||||||
|
if (raw <= 0) |
||||||
|
return context.getResources().getColor(R.color.ledgreen); |
||||||
|
return raw; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether the background service should report to ADW Launcher |
||||||
|
* @return True if the user want Transdroid to report to ADW Launcher |
||||||
|
*/ |
||||||
|
public boolean shouldReportToAdwLauncher() { |
||||||
|
return prefs.getBoolean("notifications_adwnotify", false); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
package org.transdroid.lite.app.settings; |
||||||
|
|
||||||
|
import org.transdroid.lite.gui.navigation.FilterItem; |
||||||
|
|
||||||
|
import android.net.Uri; |
||||||
|
import android.text.TextUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents a user-specified RSS feed. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class RssfeedSetting implements FilterItem { |
||||||
|
|
||||||
|
private static final String DEFAULT_NAME = "Default"; |
||||||
|
|
||||||
|
private final int order; |
||||||
|
private final String name; |
||||||
|
private final String url; |
||||||
|
private final boolean requiresAuth; |
||||||
|
private String lastNew; |
||||||
|
|
||||||
|
public RssfeedSetting(int order, String name, String baseUrl, boolean needsAuth) { |
||||||
|
this.order = order; |
||||||
|
this.name = name; |
||||||
|
this.url = baseUrl; |
||||||
|
this.requiresAuth = needsAuth; |
||||||
|
this.lastNew = null; |
||||||
|
} |
||||||
|
|
||||||
|
public int getOrder() { |
||||||
|
return order; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
if (!TextUtils.isEmpty(name)) |
||||||
|
return name; |
||||||
|
if (!TextUtils.isEmpty(url)) |
||||||
|
return Uri.parse(url).getHost(); |
||||||
|
return DEFAULT_NAME; |
||||||
|
} |
||||||
|
|
||||||
|
public String getUrl() { |
||||||
|
return url; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean requiresExternalAuthentication() { |
||||||
|
return requiresAuth; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the URL of the item that was the newest last time we checked this feed |
||||||
|
* @return The last new item's URL as URL-encoded string |
||||||
|
*/ |
||||||
|
public String getLastNew() { |
||||||
|
return this.lastNew; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Record the URL of what is now the last item we retrieved |
||||||
|
* @param lastNew The URL of the last new item as URL-encoded string |
||||||
|
*/ |
||||||
|
public void setLastNew(String lastNew) { |
||||||
|
this.lastNew = lastNew; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,195 @@ |
|||||||
|
package org.transdroid.lite.app.settings; |
||||||
|
|
||||||
|
import org.transdroid.daemon.Daemon; |
||||||
|
import org.transdroid.daemon.OS; |
||||||
|
import org.transdroid.lite.gui.navigation.FilterItem; |
||||||
|
|
||||||
|
import android.text.TextUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents a user-configured remote server. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class ServerSetting implements FilterItem { |
||||||
|
|
||||||
|
private static final String DEFAULT_NAME = "Default"; |
||||||
|
|
||||||
|
private final int key; |
||||||
|
private final String name; |
||||||
|
private final Daemon type; |
||||||
|
private final String address; |
||||||
|
private final String localAddress; |
||||||
|
private final String localNetwork; |
||||||
|
private final int port; |
||||||
|
private final String folder; |
||||||
|
private final boolean useAuthentication; |
||||||
|
private final String username; |
||||||
|
private final String password; |
||||||
|
private final String extraPass; |
||||||
|
private final OS os; |
||||||
|
private final String downloadDir; |
||||||
|
private final String ftpUrl; |
||||||
|
private final String ftpPassword; |
||||||
|
private final int timeout; |
||||||
|
private final boolean alarmOnFinishedDownload; |
||||||
|
private final boolean alarmOnNewTorrent; |
||||||
|
private final boolean ssl; |
||||||
|
private final boolean sslTrustAll; |
||||||
|
private final String sslTrustKey; |
||||||
|
private final boolean isAutoGenerated; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a daemon settings instance, providing full connection details |
||||||
|
* @param name A name used to identify this server to the user |
||||||
|
* @param type The server daemon type |
||||||
|
* @param address The server domain name or IP address |
||||||
|
* @param localAddress The server domain or IP address when connected to the server's local network |
||||||
|
* @param localNetwork The server's local network SSID |
||||||
|
* @param port The port on which the server daemon is running |
||||||
|
* @param sslTrustKey The specific key that will be accepted. |
||||||
|
* @param folder The server folder (like a virtual sub-folder or an SCGI mount point) |
||||||
|
* @param useAuthentication Whether to use basic authentication |
||||||
|
* @param username The user name to provide during authentication |
||||||
|
* @param password The password to provide during authentication |
||||||
|
* @param extraPass The Deluge web interface password |
||||||
|
* @param downloadDir The default download directory (which may also be used as base directory for file paths) |
||||||
|
* @param ftpUrl The partial URL to connect to when requesting FTP-style transfers |
||||||
|
* @param timeout The number of seconds to wait before timing out a connection attempt |
||||||
|
* @param isAutoGenerated Whether this setting was generated rather than manually inputed by the user |
||||||
|
*/ |
||||||
|
public ServerSetting(int key, String name, Daemon type, String address, String localAddress, String localNetwork, |
||||||
|
int port, boolean ssl, boolean sslTrustAll, String sslTrustKey, String folder, boolean useAuthentication, |
||||||
|
String username, String password, String extraPass, OS os, String downloadDir, String ftpUrl, |
||||||
|
String ftpPassword, int timeout, boolean alarmOnFinishedDownload, boolean alarmOnNewTorrent, |
||||||
|
boolean isAutoGenerated) { |
||||||
|
this.key = key; |
||||||
|
this.name = name; |
||||||
|
this.type = type; |
||||||
|
this.address = address; |
||||||
|
this.localAddress = localAddress; |
||||||
|
this.localNetwork = localNetwork; |
||||||
|
this.port = port; |
||||||
|
this.ssl = ssl; |
||||||
|
this.sslTrustAll = sslTrustAll; |
||||||
|
this.sslTrustKey = sslTrustKey; |
||||||
|
this.folder = folder; |
||||||
|
this.useAuthentication = useAuthentication; |
||||||
|
this.username = username; |
||||||
|
this.password = password; |
||||||
|
this.extraPass = extraPass; |
||||||
|
this.os = os; |
||||||
|
this.downloadDir = downloadDir; |
||||||
|
this.ftpUrl = ftpUrl; |
||||||
|
this.ftpPassword = ftpPassword; |
||||||
|
this.timeout = timeout; |
||||||
|
this.alarmOnFinishedDownload = alarmOnFinishedDownload; |
||||||
|
this.alarmOnNewTorrent = alarmOnNewTorrent; |
||||||
|
this.isAutoGenerated = isAutoGenerated; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return (name == null || name.equals("") ? DEFAULT_NAME : name); |
||||||
|
} |
||||||
|
|
||||||
|
public Daemon getType() { |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
public String getAddress() { |
||||||
|
return address; |
||||||
|
} |
||||||
|
|
||||||
|
public String getLocalAddress() { |
||||||
|
return localAddress; |
||||||
|
} |
||||||
|
|
||||||
|
public String getLocalNetwork() { |
||||||
|
return localNetwork; |
||||||
|
} |
||||||
|
|
||||||
|
public int getPort() { |
||||||
|
return port; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean getSsl() { |
||||||
|
return ssl; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean getSslTrustAll() { |
||||||
|
return sslTrustAll; |
||||||
|
} |
||||||
|
|
||||||
|
public String getSslTrustKey() { |
||||||
|
return sslTrustKey; |
||||||
|
} |
||||||
|
|
||||||
|
public String getFolder() { |
||||||
|
return folder; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean shouldUseAuthentication() { |
||||||
|
return useAuthentication; |
||||||
|
} |
||||||
|
|
||||||
|
public String getUsername() { |
||||||
|
return username; |
||||||
|
} |
||||||
|
|
||||||
|
public String getPassword() { |
||||||
|
return password; |
||||||
|
} |
||||||
|
|
||||||
|
public String getExtraPassword() { |
||||||
|
return extraPass; |
||||||
|
} |
||||||
|
|
||||||
|
public OS getOS() { |
||||||
|
return os; |
||||||
|
} |
||||||
|
|
||||||
|
public String getDownloadDir() { |
||||||
|
return downloadDir; |
||||||
|
} |
||||||
|
|
||||||
|
public String getFtpUrl() { |
||||||
|
return ftpUrl; |
||||||
|
} |
||||||
|
|
||||||
|
public String getFtpPassword() { |
||||||
|
return ftpPassword; |
||||||
|
} |
||||||
|
|
||||||
|
public int getTimeoutInMilliseconds() { |
||||||
|
return timeout * 1000; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean shouldAlarmOnFinishedDownload() { |
||||||
|
return alarmOnFinishedDownload; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean shouldAlarmOnNewTorrent() { |
||||||
|
return alarmOnNewTorrent; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isAutoGenerated() { |
||||||
|
return isAutoGenerated; |
||||||
|
} |
||||||
|
|
||||||
|
public int getOrder() { |
||||||
|
return this.key; |
||||||
|
} |
||||||
|
|
||||||
|
public String getHumanReadableIdentifier() { |
||||||
|
if (isAutoGenerated) { |
||||||
|
// Hide the 'implementation details'; just give the username and server
|
||||||
|
return (this.shouldUseAuthentication() && !TextUtils.isEmpty(this.getUsername()) ? this.getUsername() + "@" |
||||||
|
: "") + getAddress(); |
||||||
|
} |
||||||
|
return (this.ssl ? "https://" : "http://") |
||||||
|
+ (this.shouldUseAuthentication() && !TextUtils.isEmpty(this.getUsername()) ? this.getUsername() + "@" |
||||||
|
: "") + getAddress() + ":" + getPort() |
||||||
|
+ (Daemon.supportsCustomFolder(getType()) && getFolder() != null ? getFolder() : ""); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
package org.transdroid.lite.app.settings; |
||||||
|
|
||||||
|
import org.transdroid.lite.gui.navigation.FilterItem; |
||||||
|
|
||||||
|
import android.net.Uri; |
||||||
|
import android.text.TextUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents a user-specified website that can be searched (by starting the browser, rather than in-app) |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class WebsearchSetting implements FilterItem { |
||||||
|
|
||||||
|
private static final String DEFAULT_NAME = "Default"; |
||||||
|
private static final String KEY_PREFIX = "websearch_"; |
||||||
|
|
||||||
|
private final int order; |
||||||
|
private final String name; |
||||||
|
private final String baseUrl; |
||||||
|
|
||||||
|
public WebsearchSetting(int order, String name, String baseUrl) { |
||||||
|
this.order = order; |
||||||
|
this.name = name; |
||||||
|
this.baseUrl = baseUrl; |
||||||
|
} |
||||||
|
|
||||||
|
public int getOrder() { |
||||||
|
return order; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
if (!TextUtils.isEmpty(name)) |
||||||
|
return name; |
||||||
|
if (!TextUtils.isEmpty(baseUrl)) |
||||||
|
return Uri.parse(baseUrl).getHost(); |
||||||
|
return DEFAULT_NAME; |
||||||
|
} |
||||||
|
|
||||||
|
public String getBaseUrl() { |
||||||
|
return baseUrl; |
||||||
|
} |
||||||
|
|
||||||
|
public String getKey() { |
||||||
|
return KEY_PREFIX + getOrder(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,110 @@ |
|||||||
|
package org.transdroid.lite.gui.lists; |
||||||
|
|
||||||
|
import org.transdroid.core.R; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.res.TypedArray; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Paint; |
||||||
|
import android.graphics.RectF; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
/** |
||||||
|
* Draws a progress bar indicating the download progress as well as the torrent status. |
||||||
|
* |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class TorrentProgressBar extends View { |
||||||
|
|
||||||
|
private final float scale = getContext().getResources().getDisplayMetrics().density; |
||||||
|
private final int MINIMUM_HEIGHT = (int) (2 * scale + 0.5f); |
||||||
|
// private final int RIGHT_MARGIN = (int)(3 * scale + 0.5f);
|
||||||
|
|
||||||
|
private int progress; |
||||||
|
private boolean isActive; |
||||||
|
private boolean isError; |
||||||
|
private final Paint notdonePaint = new Paint(); |
||||||
|
private final Paint inactiveDonePaint = new Paint(); |
||||||
|
private final Paint inactivePaint = new Paint(); |
||||||
|
private final Paint progressPaint = new Paint(); |
||||||
|
private final Paint donePaint = new Paint(); |
||||||
|
private final Paint errorPaint = new Paint(); |
||||||
|
private final RectF fullRect = new RectF(); |
||||||
|
private final RectF progressRect = new RectF(); |
||||||
|
|
||||||
|
public void setProgress(int progress) { |
||||||
|
this.progress = progress; |
||||||
|
this.invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setActive(boolean isActive) { |
||||||
|
this.isActive = isActive; |
||||||
|
this.invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setError(boolean isError) { |
||||||
|
this.isError = isError; |
||||||
|
this.invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
public TorrentProgressBar(Context context) { |
||||||
|
super(context); |
||||||
|
initPaints(); |
||||||
|
} |
||||||
|
|
||||||
|
public TorrentProgressBar(Context context, AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
initPaints(); |
||||||
|
|
||||||
|
// Parse any set attributes from XML
|
||||||
|
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TorrentProgressBar); |
||||||
|
if (a.hasValue(R.styleable.TorrentProgressBar_progress)) { |
||||||
|
this.progress = a.getIndex(R.styleable.TorrentProgressBar_progress); |
||||||
|
this.isActive = a.getBoolean(R.styleable.TorrentProgressBar_isActive, false); |
||||||
|
} |
||||||
|
a.recycle(); |
||||||
|
} |
||||||
|
|
||||||
|
private void initPaints() { |
||||||
|
notdonePaint.setColor(0xFFEEEEEE); |
||||||
|
inactiveDonePaint.setColor(0xFFA759D4); |
||||||
|
inactivePaint.setColor(0xFF9E9E9E); |
||||||
|
progressPaint.setColor(0xFF42A8FA); |
||||||
|
donePaint.setColor(0xFF8CCF29); |
||||||
|
errorPaint.setColor(0xFFDE3939); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
||||||
|
int ws = MeasureSpec.getSize(widthMeasureSpec);// - RIGHT_MARGIN;
|
||||||
|
int hs = Math.max(getHeight(), MINIMUM_HEIGHT); |
||||||
|
setMeasuredDimension(ws, hs); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onDraw(Canvas canvas) { |
||||||
|
super.onDraw(canvas); |
||||||
|
|
||||||
|
int height = getHeight(); |
||||||
|
int width = getWidth(); |
||||||
|
fullRect.set(0, 0, width, height); |
||||||
|
|
||||||
|
// Error?
|
||||||
|
if (isError) { |
||||||
|
canvas.drawRect(fullRect, errorPaint); |
||||||
|
} else { |
||||||
|
// Background rounded rectangle
|
||||||
|
canvas.drawRect(fullRect, notdonePaint); |
||||||
|
|
||||||
|
// Foreground progress indicator
|
||||||
|
if (progress > 0) { |
||||||
|
progressRect.set(0, 0, width * ((float) progress / 100), height); |
||||||
|
canvas.drawRect(progressRect, (isActive ? (progress == 100 ? donePaint : progressPaint) |
||||||
|
: (progress == 100 ? inactiveDonePaint : inactivePaint))); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package org.transdroid.lite.gui.navigation; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents some label that is active or available on the server. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class Label implements FilterItem { |
||||||
|
|
||||||
|
private final String name; |
||||||
|
|
||||||
|
public Label(String name) { |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return this.name; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
package org.transdroid.lite.gui.navigation; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.transdroid.core.R; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
|
||||||
|
/** |
||||||
|
* Enumeration of all status types, which filter the list of shown torrents based on transfer activity. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public enum StatusType { |
||||||
|
|
||||||
|
ShowAll { |
||||||
|
StatusTypeFilter getFilterItem(Context context) { |
||||||
|
return new StatusTypeFilter(context.getString(R.string.navigation_status_showall)); |
||||||
|
} |
||||||
|
}, |
||||||
|
OnlyDownloading { |
||||||
|
StatusTypeFilter getFilterItem(Context context) { |
||||||
|
return new StatusTypeFilter(context.getString(R.string.navigation_status_onlydown)); |
||||||
|
} |
||||||
|
}, |
||||||
|
OnlyUploading { |
||||||
|
StatusTypeFilter getFilterItem(Context context) { |
||||||
|
return new StatusTypeFilter(context.getString(R.string.navigation_status_onlyup)); |
||||||
|
} |
||||||
|
}, |
||||||
|
OnlyActive { |
||||||
|
StatusTypeFilter getFilterItem(Context context) { |
||||||
|
return new StatusTypeFilter(context.getString(R.string.navigation_status_onlyactive)); |
||||||
|
} |
||||||
|
}, |
||||||
|
OnlyInactive { |
||||||
|
StatusTypeFilter getFilterItem(Context context) { |
||||||
|
return new StatusTypeFilter(context.getString(R.string.navigation_status_onlyinactive)); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a list with all status types, represented as filter item that can be shown in the GUI. |
||||||
|
* @param context The Android UI context, to access translations |
||||||
|
* @return A list of filter items for all available status types |
||||||
|
*/ |
||||||
|
public static List<StatusTypeFilter> getAllStatusTypes(Context context) { |
||||||
|
return Arrays.asList(ShowAll.getFilterItem(context), OnlyDownloading.getFilterItem(context), |
||||||
|
OnlyUploading.getFilterItem(context), OnlyActive.getFilterItem(context), |
||||||
|
OnlyInactive.getFilterItem(context)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Every status type can return a filter item that represents it in the navigation |
||||||
|
* @param context The Android UI context, to access translations |
||||||
|
* @return A filter item object to show in the GUI |
||||||
|
*/ |
||||||
|
abstract StatusTypeFilter getFilterItem(Context context); |
||||||
|
|
||||||
|
public static class StatusTypeFilter implements FilterItem { |
||||||
|
|
||||||
|
private final String name; |
||||||
|
|
||||||
|
StatusTypeFilter(String name) { |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,164 @@ |
|||||||
|
package org.transdroid.lite.gui.settings; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.Bean; |
||||||
|
import org.androidannotations.annotations.EActivity; |
||||||
|
import org.transdroid.core.R; |
||||||
|
import org.transdroid.lite.app.search.SearchHelper; |
||||||
|
import org.transdroid.lite.app.search.SearchSite; |
||||||
|
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||||
|
import org.transdroid.lite.app.settings.RssfeedSetting; |
||||||
|
import org.transdroid.lite.app.settings.ServerSetting; |
||||||
|
import org.transdroid.lite.app.settings.WebsearchSetting; |
||||||
|
import org.transdroid.lite.gui.settings.RssfeedPreference.OnRssfeedClickedListener; |
||||||
|
import org.transdroid.lite.gui.settings.ServerPreference.OnServerClickedListener; |
||||||
|
import org.transdroid.lite.gui.settings.WebsearchPreference.OnWebsearchClickedListener; |
||||||
|
|
||||||
|
import android.os.Bundle; |
||||||
|
import android.preference.ListPreference; |
||||||
|
import android.preference.Preference; |
||||||
|
import android.preference.Preference.OnPreferenceClickListener; |
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockPreferenceActivity; |
||||||
|
|
||||||
|
/** |
||||||
|
* The main activity that provides access to all application settings. It shows the configured serves, web search sites |
||||||
|
* and RSS feeds along with other general settings. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EActivity |
||||||
|
public class MainSettingsActivity extends SherlockPreferenceActivity { |
||||||
|
|
||||||
|
@Bean |
||||||
|
protected ApplicationSettings applicationSettings; |
||||||
|
@Bean |
||||||
|
protected SearchHelper searchHelper; |
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") |
||||||
|
@Override |
||||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
|
||||||
|
// Load the preference menu and attack actions
|
||||||
|
addPreferencesFromResource(R.xml.pref_main); |
||||||
|
findPreference("header_addserver").setOnPreferenceClickListener(onAddServer); |
||||||
|
findPreference("header_addwebsearch").setOnPreferenceClickListener(onAddWebsearch); |
||||||
|
findPreference("header_rssfeed").setOnPreferenceClickListener(onAddRssfeed); |
||||||
|
findPreference("header_background").setOnPreferenceClickListener(onBackgroundSettings); |
||||||
|
findPreference("header_system").setOnPreferenceClickListener(onSystemSettings); |
||||||
|
|
||||||
|
// Add existing servers
|
||||||
|
List<ServerSetting> servers = applicationSettings.getServerSettings(); |
||||||
|
for (ServerSetting serverSetting : servers) { |
||||||
|
getPreferenceScreen().addPreference( |
||||||
|
new ServerPreference(this).setServerSetting(serverSetting).setOnServerClickedListener( |
||||||
|
onServerClicked)); |
||||||
|
} |
||||||
|
|
||||||
|
// Add existing websearch sites
|
||||||
|
List<WebsearchSetting> websearches = applicationSettings.getWebsearchSettings(); |
||||||
|
for (WebsearchSetting websearchSetting : websearches) { |
||||||
|
getPreferenceScreen().addPreference( |
||||||
|
new WebsearchPreference(this).setWebsearchSetting(websearchSetting).setOnWebsearchClickedListener( |
||||||
|
onWebsearchClicked)); |
||||||
|
} |
||||||
|
|
||||||
|
// Add existing RSS feeds
|
||||||
|
List<RssfeedSetting> rssfeeds = applicationSettings.getRssfeedSettings(); |
||||||
|
for (RssfeedSetting rssfeedSetting : rssfeeds) { |
||||||
|
getPreferenceScreen().addPreference( |
||||||
|
new RssfeedPreference(this).setRssfeedSetting(rssfeedSetting).setOnRssfeedClickedListener( |
||||||
|
onRssfeedClicked)); |
||||||
|
} |
||||||
|
|
||||||
|
// Construct list of all available search sites, in-app and web
|
||||||
|
ListPreference setSite = (ListPreference) findPreference("header_setsearchsite"); |
||||||
|
// Retrieve the available in-app search sites (using the Torrent Search package)
|
||||||
|
List<SearchSite> searchsites = searchHelper.getAvailableSites(); |
||||||
|
List<String> siteNames = new ArrayList<String>(websearches.size() + searchsites.size()); |
||||||
|
List<String> siteValues = new ArrayList<String>(websearches.size() + searchsites.size()); |
||||||
|
for (SearchSite searchSite : searchsites) { |
||||||
|
siteNames.add(searchSite.getName()); |
||||||
|
siteValues.add(searchSite.getKey()); |
||||||
|
} |
||||||
|
for (WebsearchSetting websearch : websearches) { |
||||||
|
siteNames.add(websearch.getName()); |
||||||
|
siteValues.add(websearch.getKey()); |
||||||
|
} |
||||||
|
// Supply the Preference list names and values
|
||||||
|
setSite.setEntries(siteNames.toArray(new String[siteNames.size()])); |
||||||
|
setSite.setEntryValues(siteValues.toArray(new String[siteValues.size()])); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onBuildHeaders(List<Header> target) { |
||||||
|
// TODO: Add two-pane support in settings
|
||||||
|
super.onBuildHeaders(target); |
||||||
|
} |
||||||
|
|
||||||
|
private OnPreferenceClickListener onAddServer = new OnPreferenceClickListener() { |
||||||
|
@Override |
||||||
|
public boolean onPreferenceClick(Preference preference) { |
||||||
|
ServerSettingsActivity_.intent(MainSettingsActivity.this).start(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private OnPreferenceClickListener onAddWebsearch = new OnPreferenceClickListener() { |
||||||
|
@Override |
||||||
|
public boolean onPreferenceClick(Preference preference) { |
||||||
|
WebsearchSettingsActivity_.intent(MainSettingsActivity.this).start(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private OnPreferenceClickListener onAddRssfeed = new OnPreferenceClickListener() { |
||||||
|
@Override |
||||||
|
public boolean onPreferenceClick(Preference preference) { |
||||||
|
RssfeedSettingsActivity_.intent(MainSettingsActivity.this).start(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private OnPreferenceClickListener onBackgroundSettings = new OnPreferenceClickListener() { |
||||||
|
@Override |
||||||
|
public boolean onPreferenceClick(Preference preference) { |
||||||
|
OtherSettingsActivity_.intent(MainSettingsActivity.this).preferencesResourceID(R.xml.pref_notifications) |
||||||
|
.start(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private OnPreferenceClickListener onSystemSettings = new OnPreferenceClickListener() { |
||||||
|
@Override |
||||||
|
public boolean onPreferenceClick(Preference preference) { |
||||||
|
OtherSettingsActivity_.intent(MainSettingsActivity.this).preferencesResourceID(R.xml.pref_about).start(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private OnServerClickedListener onServerClicked = new OnServerClickedListener() { |
||||||
|
@Override |
||||||
|
public void onServerClicked(ServerSetting serverSetting) { |
||||||
|
ServerSettingsActivity_.intent(MainSettingsActivity.this).key(serverSetting.getOrder()).start(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private OnWebsearchClickedListener onWebsearchClicked = new OnWebsearchClickedListener() { |
||||||
|
@Override |
||||||
|
public void onWebsearchClicked(WebsearchSetting websearchSetting) { |
||||||
|
WebsearchSettingsActivity_.intent(MainSettingsActivity.this).key(websearchSetting.getOrder()).start(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private OnRssfeedClickedListener onRssfeedClicked = new OnRssfeedClickedListener() { |
||||||
|
@Override |
||||||
|
public void onRssfeedClicked(RssfeedSetting rssfeedSetting) { |
||||||
|
RssfeedSettingsActivity_.intent(MainSettingsActivity.this).key(rssfeedSetting.getOrder()).start(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
package org.transdroid.lite.gui.settings; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.Bean; |
||||||
|
import org.androidannotations.annotations.EActivity; |
||||||
|
import org.androidannotations.annotations.Extra; |
||||||
|
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||||
|
|
||||||
|
import android.os.Bundle; |
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockPreferenceActivity; |
||||||
|
|
||||||
|
@EActivity |
||||||
|
public class OtherSettingsActivity extends SherlockPreferenceActivity { |
||||||
|
|
||||||
|
@Extra |
||||||
|
protected int preferencesResourceID; |
||||||
|
|
||||||
|
@Bean |
||||||
|
protected ApplicationSettings applicationSettings; |
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") |
||||||
|
@Override |
||||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
|
||||||
|
// Just load the preferences from XML, of which the ID is supplied as extra
|
||||||
|
addPreferencesFromResource(preferencesResourceID); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package org.transdroid.lite.gui.settings; |
||||||
|
|
||||||
|
import org.transdroid.lite.app.settings.RssfeedSetting; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.preference.Preference; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents a {@link RssfeedSetting} in a preferences screen. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class RssfeedPreference extends Preference { |
||||||
|
|
||||||
|
private static final int ORDER_START = 201; |
||||||
|
|
||||||
|
private RssfeedSetting rssfeedSetting; |
||||||
|
private OnRssfeedClickedListener onRssfeedClickedListener = null; |
||||||
|
|
||||||
|
public RssfeedPreference(Context context) { |
||||||
|
super(context); |
||||||
|
setOnPreferenceClickListener(onPreferenceClicked); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the RSS feed settings object that is bound to this preference item |
||||||
|
* @param rssfeedSetting The RSS feed settings |
||||||
|
* @return Itself, for method chaining |
||||||
|
*/ |
||||||
|
public RssfeedPreference setRssfeedSetting(RssfeedSetting rssfeedSetting) { |
||||||
|
this.rssfeedSetting = rssfeedSetting; |
||||||
|
setTitle(rssfeedSetting.getName()); |
||||||
|
setOrder(ORDER_START + rssfeedSetting.getOrder()); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set a listener that will be notified of click events on this preference |
||||||
|
* @param onRssfeedClickedListener The click listener to register |
||||||
|
* @return Itself, for method chaining |
||||||
|
*/ |
||||||
|
public RssfeedPreference setOnRssfeedClickedListener(OnRssfeedClickedListener onRssfeedClickedListener) { |
||||||
|
this.onRssfeedClickedListener = onRssfeedClickedListener; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
private OnPreferenceClickListener onPreferenceClicked = new OnPreferenceClickListener() { |
||||||
|
@Override |
||||||
|
public boolean onPreferenceClick(Preference preference) { |
||||||
|
if (onRssfeedClickedListener != null) |
||||||
|
onRssfeedClickedListener.onRssfeedClicked(rssfeedSetting); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public interface OnRssfeedClickedListener { |
||||||
|
public void onRssfeedClicked(RssfeedSetting rssfeedSetting); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
package org.transdroid.lite.gui.settings; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.Bean; |
||||||
|
import org.androidannotations.annotations.EActivity; |
||||||
|
import org.androidannotations.annotations.Extra; |
||||||
|
import org.transdroid.core.R; |
||||||
|
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||||
|
|
||||||
|
import android.os.Bundle; |
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockPreferenceActivity; |
||||||
|
|
||||||
|
/** |
||||||
|
* Activity that allows for a configuration of some RSS feed. The key can be supplied to update an |
||||||
|
* existing RSS feed setting instead of creating a new one. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EActivity |
||||||
|
public class RssfeedSettingsActivity extends SherlockPreferenceActivity { |
||||||
|
|
||||||
|
@Extra |
||||||
|
protected int key = -1; |
||||||
|
|
||||||
|
@Bean |
||||||
|
protected ApplicationSettings applicationSettings; |
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") |
||||||
|
@Override |
||||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
|
||||||
|
// Load the raw preferences to show in this screen
|
||||||
|
addPreferencesFromResource(R.xml.pref_rssfeed); |
||||||
|
|
||||||
|
// Bind the preferences to the correct storage key, e.g. the first RSS feed setting stores its URL in the
|
||||||
|
// 'rssfeed_url_0' shared preferences field
|
||||||
|
if (key < 0) { |
||||||
|
key = applicationSettings.getMaxRssfeed() + 1; |
||||||
|
} |
||||||
|
findPreference("rssfeed_name").setKey("rssfeed_name_" + key); |
||||||
|
findPreference("rssfeed_url").setKey("rssfeed_url_" + key); |
||||||
|
findPreference("rssfeed_reqauth").setKey("rssfeed_reqauth_" + key); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package org.transdroid.lite.gui.settings; |
||||||
|
|
||||||
|
import org.transdroid.lite.app.settings.ServerSetting; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.preference.Preference; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents a {@link ServerSetting} in a preferences screen. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class ServerPreference extends Preference { |
||||||
|
|
||||||
|
private static final int ORDER_START = 1; |
||||||
|
|
||||||
|
private ServerSetting serverSetting; |
||||||
|
private OnServerClickedListener onServerClickedListener = null; |
||||||
|
|
||||||
|
public ServerPreference(Context context) { |
||||||
|
super(context); |
||||||
|
setOnPreferenceClickListener(onPreferenceClicked); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the server settings object that is bound to this preference item |
||||||
|
* @param serverSetting The server settings |
||||||
|
* @return Itself, for method chaining |
||||||
|
*/ |
||||||
|
public ServerPreference setServerSetting(ServerSetting serverSetting) { |
||||||
|
this.serverSetting = serverSetting; |
||||||
|
setTitle(serverSetting.getHumanReadableIdentifier()); |
||||||
|
setOrder(ORDER_START + serverSetting.getOrder()); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set a listener that will be notified of click events on this preference |
||||||
|
* @param onServerClickedListener The click listener to register |
||||||
|
* @return Itself, for method chaining |
||||||
|
*/ |
||||||
|
public ServerPreference setOnServerClickedListener(OnServerClickedListener onServerClickedListener) { |
||||||
|
this.onServerClickedListener = onServerClickedListener; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
private OnPreferenceClickListener onPreferenceClicked = new OnPreferenceClickListener() { |
||||||
|
@Override |
||||||
|
public boolean onPreferenceClick(Preference preference) { |
||||||
|
if (onServerClickedListener != null) |
||||||
|
onServerClickedListener.onServerClicked(serverSetting); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public interface OnServerClickedListener { |
||||||
|
public void onServerClicked(ServerSetting serverSetting); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,94 @@ |
|||||||
|
package org.transdroid.lite.gui.settings; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.Bean; |
||||||
|
import org.androidannotations.annotations.EActivity; |
||||||
|
import org.androidannotations.annotations.Extra; |
||||||
|
import org.transdroid.daemon.Daemon; |
||||||
|
import org.transdroid.core.R; |
||||||
|
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||||
|
|
||||||
|
import android.content.SharedPreferences; |
||||||
|
import android.os.Bundle; |
||||||
|
import android.preference.Preference; |
||||||
|
import android.preference.Preference.OnPreferenceChangeListener; |
||||||
|
import android.preference.PreferenceManager; |
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockPreferenceActivity; |
||||||
|
|
||||||
|
/** |
||||||
|
* Activity that allows for a configuration of a server. The key can be supplied to update an existing server setting |
||||||
|
* instead of creating a new one. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EActivity |
||||||
|
public class ServerSettingsActivity extends SherlockPreferenceActivity { |
||||||
|
|
||||||
|
@Extra |
||||||
|
protected int key = -1; |
||||||
|
|
||||||
|
@Bean |
||||||
|
protected ApplicationSettings applicationSettings; |
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") |
||||||
|
@Override |
||||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
|
||||||
|
// Load the raw preferences to show in this screen
|
||||||
|
addPreferencesFromResource(R.xml.pref_server); |
||||||
|
|
||||||
|
// Bind the preferences to the correct storage key, e.g. the first server setting stores its address in the
|
||||||
|
// 'server_address_0' shared preferences field
|
||||||
|
if (key < 0) { |
||||||
|
key = applicationSettings.getMaxWebsearch() + 1; |
||||||
|
} |
||||||
|
findPreference("server_name").setKey("server_name_" + key); |
||||||
|
findPreference("server_type").setKey("server_type_" + key); |
||||||
|
findPreference("server_address").setKey("server_address_" + key); |
||||||
|
findPreference("server_port").setKey("server_port_" + key); |
||||||
|
findPreference("server_user").setKey("server_user_" + key); |
||||||
|
findPreference("server_pass").setKey("server_pass_" + key); |
||||||
|
findPreference("server_extrapass").setKey("server_extrapass_" + key); |
||||||
|
findPreference("server_localaddress").setKey("server_localaddress_" + key); |
||||||
|
findPreference("server_localnetwork").setKey("server_localnetwork_" + key); |
||||||
|
findPreference("server_folder").setKey("server_folder_" + key); |
||||||
|
findPreference("server_timeout").setKey("server_timeout_" + key); |
||||||
|
findPreference("server_alamrfinished").setKey("server_alamrfinished_" + key); |
||||||
|
findPreference("server_alarnew").setKey("server_alarnew_" + key); |
||||||
|
findPreference("server_os").setKey("server_os_" + key); |
||||||
|
findPreference("server_downloaddir").setKey("server_downloaddir_" + key); |
||||||
|
findPreference("server_ftpurl").setKey("server_ftpurl_" + key); |
||||||
|
findPreference("server_ftppass").setKey("server_ftppass_" + key); |
||||||
|
findPreference("server_sslenabled").setKey("server_sslenabled_" + key); |
||||||
|
findPreference("server_ssltrustall").setKey("server_ssltrustall_" + key); |
||||||
|
findPreference("server_ssltrustkey").setKey("server_ssltrustkey_" + key); |
||||||
|
|
||||||
|
// Monitor preference changes
|
||||||
|
getPreferenceScreen().setOnPreferenceChangeListener(onPreferenceChangeListener); |
||||||
|
} |
||||||
|
|
||||||
|
private OnPreferenceChangeListener onPreferenceChangeListener = new OnPreferenceChangeListener() { |
||||||
|
@Override |
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) { |
||||||
|
updatePreferenceAvailability(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") |
||||||
|
private void updatePreferenceAvailability() { |
||||||
|
|
||||||
|
// Use daemon factory to see if the newly selected daemon supports the feature
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); |
||||||
|
Daemon daemonType = Daemon.fromCode(prefs.getString("server_type_" + key, null)); |
||||||
|
findPreference("server_extrapass_" + key).setEnabled(Daemon.supportsExtraPassword(daemonType)); |
||||||
|
findPreference("server_folder_" + key).setEnabled(daemonType == null? false: Daemon.supportsCustomFolder(daemonType)); |
||||||
|
findPreference("server_downloaddir_" + key).setEnabled(daemonType == null? false: Daemon.needsManualPathSpecified(daemonType)); |
||||||
|
//findPreference("server_ssltrustkey_" + key).setEnabled(sslValue && !sslTAValue);
|
||||||
|
|
||||||
|
// Adjust title texts accordingly
|
||||||
|
findPreference("server_folder_" + key).setTitle(daemonType == Daemon.rTorrent? R.string.pref_scgifolder: R.string.pref_folder); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package org.transdroid.lite.gui.settings; |
||||||
|
|
||||||
|
import org.transdroid.lite.app.settings.WebsearchSetting; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.preference.Preference; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents a {@link WebsearchSetting} in a preferences screen. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class WebsearchPreference extends Preference { |
||||||
|
|
||||||
|
private static final int ORDER_START = 102; |
||||||
|
|
||||||
|
private WebsearchSetting websearchSetting; |
||||||
|
private OnWebsearchClickedListener onWebsearchClickedListener = null; |
||||||
|
|
||||||
|
public WebsearchPreference(Context context) { |
||||||
|
super(context); |
||||||
|
setOnPreferenceClickListener(onPreferenceClicked); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the websearch settings object that is bound to this preference item |
||||||
|
* @param websearchSetting The websearch settings |
||||||
|
* @return Itself, for method chaining |
||||||
|
*/ |
||||||
|
public WebsearchPreference setWebsearchSetting(WebsearchSetting websearchSetting) { |
||||||
|
this.websearchSetting = websearchSetting; |
||||||
|
setTitle(websearchSetting.getName()); |
||||||
|
setOrder(ORDER_START + websearchSetting.getOrder()); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set a listener that will be notified of click events on this preference |
||||||
|
* @param onWebsearchClickedListener The click listener to register |
||||||
|
* @return Itself, for method chaining |
||||||
|
*/ |
||||||
|
public WebsearchPreference setOnWebsearchClickedListener(OnWebsearchClickedListener onWebsearchClickedListener) { |
||||||
|
this.onWebsearchClickedListener = onWebsearchClickedListener; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
private OnPreferenceClickListener onPreferenceClicked = new OnPreferenceClickListener() { |
||||||
|
@Override |
||||||
|
public boolean onPreferenceClick(Preference preference) { |
||||||
|
if (onWebsearchClickedListener != null) |
||||||
|
onWebsearchClickedListener.onWebsearchClicked(websearchSetting); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public interface OnWebsearchClickedListener { |
||||||
|
public void onWebsearchClicked(WebsearchSetting serverSetting); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
package org.transdroid.lite.gui.settings; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.Bean; |
||||||
|
import org.androidannotations.annotations.EActivity; |
||||||
|
import org.androidannotations.annotations.Extra; |
||||||
|
import org.transdroid.core.R; |
||||||
|
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||||
|
|
||||||
|
import android.os.Bundle; |
||||||
|
|
||||||
|
import com.actionbarsherlock.app.SherlockPreferenceActivity; |
||||||
|
|
||||||
|
/** |
||||||
|
* Activity that allows for a configuration of a web search site. The key can be supplied to update an existing web |
||||||
|
* search site setting instead of creating a new one. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EActivity |
||||||
|
public class WebsearchSettingsActivity extends SherlockPreferenceActivity { |
||||||
|
|
||||||
|
@Extra |
||||||
|
protected int key = -1; |
||||||
|
|
||||||
|
@Bean |
||||||
|
protected ApplicationSettings applicationSettings; |
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") |
||||||
|
@Override |
||||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||||
|
super.onCreate(savedInstanceState); |
||||||
|
|
||||||
|
// Load the raw preferences to show in this screen
|
||||||
|
addPreferencesFromResource(R.xml.pref_websearch); |
||||||
|
|
||||||
|
// Bind the preferences to the correct storage key, e.g. the first site setting stores its URL in the
|
||||||
|
// 'websearch_baseurl_0' shared preferences field
|
||||||
|
if (key < 0) { |
||||||
|
key = applicationSettings.getMaxWebsearch() + 1; |
||||||
|
} |
||||||
|
findPreference("websearch_name").setKey("websearch_name_" + key); |
||||||
|
findPreference("websearch_baseurl").setKey("websearch_baseurl_" + key); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |