() {
52 | @Override
53 | public int compare(Bookmark s1, Bookmark s2) {
54 | return s1.getUrl().compareToIgnoreCase(s2.getUrl());
55 | }
56 | });
57 | clear();
58 | for(int i = 0; i < simpleClass.size(); i++){
59 | super.add(simpleClass.get(i));
60 | }
61 | } catch (Exception ignored) {
62 |
63 | }
64 | }
65 |
66 | @Override
67 | public boolean add(Bookmark object) {
68 | boolean r = super.add(object);
69 | if(isAutoSave()) save();
70 | return r;
71 | }
72 |
73 | @Override
74 | public boolean remove(Object object) {
75 | boolean r = super.remove(object);
76 | if(isAutoSave()) save();
77 | return r;
78 | }
79 |
80 | @Override
81 | public Bookmark set(int index, Bookmark object) {
82 | Bookmark r = super.set(index, object);
83 | if(isAutoSave()) save();
84 | return r;
85 | }
86 |
87 | public void addAsPublic(Bookmark bookmark) {
88 | bookmark.setInternal(false);
89 | int idx = indexOf(bookmark);
90 | if(idx == -1){
91 | add(bookmark);
92 | } else {
93 | set(idx, bookmark);
94 | }
95 | }
96 |
97 | public Bookmark findItem(ViewModel item){
98 | Bookmark b = new BookmarkManager.Bookmark(Parser.getInstance().getParserId(), Parser.getInstance().getPageLink(item));
99 | int idx = indexOf(b);
100 | if(idx == -1){
101 | return null;
102 | } else {
103 | return get(idx);
104 | }
105 | }
106 |
107 | private boolean isAutoSave() {
108 | return autoSave;
109 | }
110 |
111 | private void setAutoSave(boolean autoSave) {
112 | this.autoSave = autoSave;
113 | }
114 |
115 | public static class Bookmark implements Serializable{
116 | private int parserId;
117 | private String url;
118 | private int season = 0;
119 | private int episode = 0;
120 | private boolean internal = true;
121 |
122 | public Bookmark(int parserId, String url) {
123 | this.parserId = parserId;
124 | this.url = url;
125 | }
126 |
127 | public int getParserId() {
128 | return parserId;
129 | }
130 |
131 | public String getUrl() {
132 | return url;
133 | }
134 |
135 | public void setUrl(String url) {
136 | this.url = url;
137 | }
138 |
139 | public int getEpisode() {
140 | return episode;
141 | }
142 |
143 | public void setEpisode(int episode) {
144 | this.episode = episode;
145 | }
146 |
147 | public int getSeason() {
148 | return season;
149 | }
150 |
151 | public void setSeason(int season) {
152 | this.season = season;
153 | }
154 |
155 | public boolean isInternal() {
156 | return internal;
157 | }
158 |
159 | public void setInternal(boolean internal) {
160 | this.internal = internal;
161 | }
162 |
163 | @Override
164 | public boolean equals(Object o) {
165 | if(o instanceof Bookmark){
166 | Bookmark b = (Bookmark)o;
167 | return b.getParserId() == this.getParserId() && TextUtils.equals(b.getUrl(), this.getUrl());
168 | }
169 | return super.equals(o);
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/utils/CloudflareDdosInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.utils;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.os.SystemClock;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.webkit.CookieManager;
9 | import android.webkit.CookieSyncManager;
10 | import android.webkit.WebView;
11 | import android.webkit.WebViewClient;
12 |
13 | import com.ov3rk1ll.kinocast.api.Parser;
14 | import com.ov3rk1ll.kinocast.ui.MainActivity;
15 |
16 | import java.io.IOException;
17 |
18 | import okhttp3.Cookie;
19 | import okhttp3.Interceptor;
20 | import okhttp3.Request;
21 | import okhttp3.Response;
22 |
23 | @SuppressWarnings("deprecation")
24 | public class CloudflareDdosInterceptor implements Interceptor {
25 | private static final String TAG = CloudflareDdosInterceptor.class.getSimpleName();
26 |
27 | private Context context;
28 |
29 | public CloudflareDdosInterceptor(Context context) {
30 | this.context = context;
31 | }
32 |
33 | @Override
34 | public Response intercept(final Chain chain) throws IOException {
35 | final Request request = chain.request();
36 | final Response response = chain.proceed(request);
37 | if(response.code() == 503) {
38 | Log.d(TAG, "intercept: Status " + response.code() + " for " + request.url());
39 | Log.v(TAG, "intercept: try to handle request to " + request.url().toString());
40 | String body = response.body().string();
41 | final boolean[] requestDone = {false};
42 | final String[] solvedUrl = {null};
43 | if (body.contains("DDoS protection by Cloudflare") && !request.url().toString().contains("/cdn-cgi/l/chk_jschl")) {
44 | MainActivity.activity.runOnUiThread(new Runnable() {
45 | @SuppressLint("SetJavaScriptEnabled")
46 | @Override
47 | public void run() {
48 | // Virtual WebView
49 | final WebView webView = MainActivity.webView;
50 |
51 | // Delete all cookies
52 | CookieSyncManager cookieSyncMngr = CookieSyncManager.createInstance(context);
53 | cookieSyncMngr.startSync();
54 | CookieManager cookieManager = CookieManager.getInstance();
55 | cookieManager.removeAllCookie();
56 | cookieManager.removeSessionCookie();
57 | cookieSyncMngr.stopSync();
58 | cookieSyncMngr.sync();
59 | cookieManager.setCookie(request.url().toString(), response.header("Set-Cookie"));
60 | cookieSyncMngr.sync();
61 |
62 | webView.setVisibility(View.GONE);
63 | webView.clearCache(true);
64 | webView.getSettings().setUserAgentString(Utils.USER_AGENT);
65 | webView.getSettings().setJavaScriptEnabled(true);
66 | webView.setWebViewClient(new WebViewClient() {
67 | @Override
68 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
69 | String raw = CookieManager.getInstance().getCookie(url);
70 | Log.v("CloudflareDdos", "shouldOverrideUrlLoading: wants to load " + url + " with cookies " + raw);
71 | solvedUrl[0] = url;
72 | requestDone[0] = true;
73 | return true;
74 | }
75 | });
76 | webView.loadUrl(request.url().toString());
77 | Log.v("CloudflareDdos", "load " + request.url().toString() + " in webview");
78 |
79 | }
80 | });
81 |
82 | int timeout = 50;
83 | // Wait for the webView to load the correct url
84 | while (!requestDone[0]){
85 | SystemClock.sleep(200);
86 | timeout--;
87 | if(timeout <= 0)
88 | break;
89 | }
90 | if(solvedUrl[0] != null) {
91 | // Store the cookies from the WebView in the OkHttpClient's jar
92 | InjectedCookieJar jar = (InjectedCookieJar) Parser.getInstance().getClient().cookieJar();
93 | String raw = CookieManager.getInstance().getCookie(solvedUrl[0]);
94 | Log.v("CloudflareDdos", "load " + solvedUrl[0] + ", raw-cookies=" + raw);
95 | String[] cookies = raw.split(";");
96 | for (String c : cookies) {
97 | jar.addCookie(Cookie.parse(request.url(), c.trim()));
98 | }
99 |
100 | // call the check url to get and store the correct cookies
101 | Parser.getInstance().getBody(solvedUrl[0]);
102 |
103 | // run the action request again
104 | Log.v(TAG, "intercept: will retry request to " + request.url());
105 | return chain.proceed(request);
106 | }
107 | return response;
108 | }
109 | }
110 | return response;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | KinoCast
5 | Einstellungen
6 | Neue Kinofilme
7 | Beliebte Filme
8 | Neuste Filme
9 | Beliebte Serien
10 | Neuste Serien
11 | Favoriten
12 | Einstellungen
13 |
14 | http://ov3rk1ll.github.io/KinoCast/update2.json
15 | Prüfe auf Update...
16 | Du hast bereists die aktuelle Version installiert
17 |
18 | Navigation öffnen
19 | Navigation schließen
20 |
21 | Details
22 | powered by KinoCast
23 | Chromecast nicht verbunden. Öffne Videoplayer…
24 | Fehler beim Auflösen des Hosts!
25 | Die Datei wurde möglicherweiße gelöscht.
26 | Lade…
27 | Staffel
28 | Episode
29 | Mirror
30 | im Browser öffnen
31 | auf IMDb anzeigen
32 | Aus Favoriten entfernen
33 | Aus Favoriten entfernt
34 | Zu Favoriten hinzufügen
35 | Zu Favoriten hinzugefügt
36 | Kein Hoster verfügbar
37 | Lautlos
38 | Suchen
39 | Suche
40 | Player
41 | Settings
42 |
43 | Abspielen
44 | Player wählen:
45 | Lade video
46 | Buffering
47 | Chromecast
48 | Video kann nicht abgespielt werden! Bitte versuche einen anderen Player.
49 | Fehler beim Abspielen
50 | Das Ansehen von Filmen verursacht hohe Datendownloads. Über eine Mobilfunkverbindung können so hohe Kosten entstehen!
51 | Trozdem fortfahren?
52 |
53 | Verbindungsfehler
54 | %1$s antwortet nicht!
55 | Wiederholen
56 |
57 | Staffel und Episode
58 | Wähle die Staffel und Episode aus die du ansehen willst hier aus
59 | Mirror
60 | Wähle den Hoster und Mirror hier aus
61 | Chromecast
62 | Verbinde dich um Filme an den Chromecast zu streamen
63 | Favoriten
64 | Füge deine Lieblingsfilme und Serien zu den Favoriten hinzu.
65 | Deine Favoriten findest du im Menü auf der linken Seite.
66 |
67 | Hole video mit ID %1$s
68 | Lade Daten von %1$s
69 | Warte für %1$s Sekunden
70 | Senden Daten an %1$s
71 | Hole Videolink
72 | Link beim ersten Versuch gefunden
73 | Link beim zweiten Versuch gefunden
74 |
75 | Hosterliste sortieren
76 | Sortiere deine Lieblingshoster
77 |
78 | Unterstütze KinoCast
79 | Gefällt dir KinoCast? Dann unterstütze uns doch mit einer kleinen Spende
80 | Jetzt spenden
81 | Nein, danke
82 | Später
83 |
84 | Hier sollte eigentlich Werbung sein. Da hier gerade keine Werbung ist würde wir und über eine kleine Unterstützung auf PayPal freuen.
85 | Spenden
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
19 |
22 |
25 |
26 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
50 |
53 |
54 |
61 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
80 |
83 |
84 |
85 |
86 |
87 |
88 |
94 |
97 |
98 |
99 |
100 |
101 |
106 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/ui/PlayerActivity.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.ui;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.content.DialogInterface;
6 | import android.media.MediaPlayer;
7 | import android.net.Uri;
8 | import android.os.Bundle;
9 | import android.os.Handler;
10 | import android.view.MotionEvent;
11 | import android.view.View;
12 | import android.widget.FrameLayout;
13 | import android.widget.VideoView;
14 |
15 | import com.ov3rk1ll.kinocast.R;
16 | import com.ov3rk1ll.kinocast.ui.util.CustomMediaController;
17 | import com.ov3rk1ll.kinocast.ui.util.SystemUiHider;
18 |
19 | /**
20 | * An example full-screen activity that shows and hides the system UI (i.e.
21 | * status bar and navigation/system bar) with user interaction.
22 | *
23 | * @see SystemUiHider
24 | */
25 | public class PlayerActivity extends Activity {
26 | private static final boolean AUTO_HIDE = true;
27 | private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
28 | private static final boolean TOGGLE_ON_CLICK = true;
29 | private static final int HIDER_FLAGS = SystemUiHider.FLAG_HIDE_NAVIGATION;
30 |
31 | private SystemUiHider mSystemUiHider;
32 | private Uri mVideoUri;
33 | private CustomMediaController mMediaController;
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 |
39 | setContentView(R.layout.activity_player);
40 |
41 | mVideoUri = getIntent().getData();
42 |
43 | final View controlsView = findViewById(R.id.fullscreen_content_controls);
44 |
45 | mMediaController = new CustomMediaController(this);
46 |
47 | mSystemUiHider = SystemUiHider.getInstance(this, getWindow().getDecorView(), HIDER_FLAGS);
48 | mSystemUiHider.setup();
49 | mSystemUiHider
50 | .setOnVisibilityChangeListener(new SystemUiHider.OnVisibilityChangeListener() {
51 | @Override
52 | public void onVisibilityChange(boolean visible) {
53 | //controlsView.setVisibility(visible ? View.VISIBLE : View.GONE);
54 | if (visible) {
55 | mMediaController.show();
56 | } else {
57 | mMediaController.hide();
58 | }
59 |
60 | if (visible && AUTO_HIDE) {
61 | delayedHide(AUTO_HIDE_DELAY_MILLIS);
62 | }
63 | }
64 | });
65 |
66 | // Set up the user interaction to manually show or hide the system UI.
67 | controlsView.setOnTouchListener(new View.OnTouchListener() {
68 | @Override
69 | public boolean onTouch(View v, MotionEvent event) {
70 | if (event.getAction() == MotionEvent.ACTION_DOWN) {
71 | if (TOGGLE_ON_CLICK) {
72 | mSystemUiHider.toggle();
73 | } else {
74 | mSystemUiHider.show();
75 | }
76 | }
77 | return true;
78 | }
79 | });
80 |
81 | }
82 |
83 | @Override
84 | protected void onPostCreate(Bundle savedInstanceState) {
85 | super.onPostCreate(savedInstanceState);
86 |
87 | final View controlsView = findViewById(R.id.fullscreen_content_controls);
88 | final VideoView videoView = (VideoView) findViewById(R.id.fullscreen_content);
89 |
90 | videoView.setVideoURI(mVideoUri);
91 |
92 | final FrameLayout decor = (FrameLayout) getWindow().getDecorView();
93 | final View videoProgressView = View.inflate(getApplicationContext(), R.layout.video_loading_progress, null);
94 |
95 | decor.addView(videoProgressView);
96 |
97 | videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
98 | @Override
99 | public void onPrepared(MediaPlayer mp) {
100 | decor.removeView(videoProgressView);
101 | videoView.setMediaController(mMediaController);
102 | mMediaController.setAnchorView(controlsView);
103 | }
104 | });
105 |
106 | videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
107 | @Override
108 | public boolean onError(MediaPlayer mp, int what, int extra) {
109 | (new AlertDialog.Builder(PlayerActivity.this))
110 | .setTitle(getString(R.string.player_error_dialog_title))
111 | .setMessage(getString(R.string.player_unsupported_format) + "\n\n(#" + what + "E" + extra + ")")
112 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
113 | @Override
114 | public void onClick(DialogInterface dialog, int which) {
115 | finish();
116 | }
117 | })
118 | .show();
119 | return true;
120 | }
121 | });
122 |
123 | videoView.start();
124 | delayedHide(100);
125 | }
126 |
127 | Handler mHideHandler = new Handler();
128 | Runnable mHideRunnable = new Runnable() {
129 | @Override
130 | public void run() {
131 | mSystemUiHider.hide();
132 | }
133 | };
134 |
135 | /**
136 | * Schedules a call to hide() in [delay] milliseconds, canceling any
137 | * previously scheduled calls.
138 | */
139 | private void delayedHide(int delayMillis) {
140 | mHideHandler.removeCallbacks(mHideRunnable);
141 | mHideHandler.postDelayed(mHideRunnable, delayMillis);
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/ui/util/SystemUiHider.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.ui.util;
2 |
3 | import android.app.Activity;
4 | import android.os.Build;
5 | import android.view.View;
6 |
7 | /**
8 | * A utility class that helps with showing and hiding system UI such as the
9 | * status bar and navigation/system bar. This class uses backward-compatibility
10 | * techniques described in
12 | * Creating Backward-Compatible UIs to ensure that devices running any
13 | * version of ndroid OS are supported. More specifically, there are separate
14 | * implementations of this abstract class: for newer devices,
15 | * {@link #getInstance} will return a {@link SystemUiHiderHoneycomb} instance,
16 | * while on older devices {@link #getInstance} will return a
17 | * {@link SystemUiHiderBase} instance.
18 | *
19 | * For more on system bars, see System Bars.
22 | *
23 | * @see android.view.View#setSystemUiVisibility(int)
24 | * @see android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN
25 | */
26 | public abstract class SystemUiHider {
27 | /**
28 | * When this flag is set, the
29 | * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN}
30 | * flag will be set on older devices, making the status bar "float" on top
31 | * of the activity layout. This is most useful when there are no controls at
32 | * the top of the activity layout.
33 | *
34 | * This flag isn't used on newer devices because the action
36 | * bar, the most important structural element of an Android app, should
37 | * be visible and not obscured by the system UI.
38 | */
39 | public static final int FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES = 0x1;
40 |
41 | /**
42 | * When this flag is set, {@link #show()} and {@link #hide()} will toggle
43 | * the visibility of the status bar. If there is a navigation bar, show and
44 | * hide will toggle low profile mode.
45 | */
46 | public static final int FLAG_FULLSCREEN = 0x2;
47 |
48 | /**
49 | * When this flag is set, {@link #show()} and {@link #hide()} will toggle
50 | * the visibility of the navigation bar, if it's present on the device and
51 | * the device allows hiding it. In cases where the navigation bar is present
52 | * but cannot be hidden, show and hide will toggle low profile mode.
53 | */
54 | public static final int FLAG_HIDE_NAVIGATION = FLAG_FULLSCREEN | 0x4;
55 |
56 | /**
57 | * The activity associated with this UI hider object.
58 | */
59 | protected Activity mActivity;
60 |
61 | /**
62 | * The view on which {@link View#setSystemUiVisibility(int)} will be called.
63 | */
64 | protected View mAnchorView;
65 |
66 | /**
67 | * The current UI hider flags.
68 | *
69 | * @see #FLAG_FULLSCREEN
70 | * @see #FLAG_HIDE_NAVIGATION
71 | * @see #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES
72 | */
73 | protected int mFlags;
74 |
75 | /**
76 | * The current visibility callback.
77 | */
78 | protected OnVisibilityChangeListener mOnVisibilityChangeListener = sDummyListener;
79 |
80 | /**
81 | * Creates and returns an instance of {@link SystemUiHider} that is
82 | * appropriate for this device. The object will be either a
83 | * {@link SystemUiHiderBase} or {@link SystemUiHiderHoneycomb} depending on
84 | * the device.
85 | *
86 | * @param activity The activity whose window's system UI should be
87 | * controlled by this class.
88 | * @param anchorView The view on which
89 | * {@link View#setSystemUiVisibility(int)} will be called.
90 | * @param flags Either 0 or any combination of {@link #FLAG_FULLSCREEN},
91 | * {@link #FLAG_HIDE_NAVIGATION}, and
92 | * {@link #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES}.
93 | */
94 | public static SystemUiHider getInstance(Activity activity, View anchorView, int flags) {
95 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
96 | return new SystemUiHiderHoneycomb(activity, anchorView, flags);
97 | } else {
98 | return new SystemUiHiderBase(activity, anchorView, flags);
99 | }
100 | }
101 |
102 | protected SystemUiHider(Activity activity, View anchorView, int flags) {
103 | mActivity = activity;
104 | mAnchorView = anchorView;
105 | mFlags = flags;
106 | }
107 |
108 | /**
109 | * Sets up the system UI hider. Should be called from
110 | * {@link Activity#onCreate}.
111 | */
112 | public abstract void setup();
113 |
114 | /**
115 | * Returns whether or not the system UI is visible.
116 | */
117 | public abstract boolean isVisible();
118 |
119 | /**
120 | * Hide the system UI.
121 | */
122 | public abstract void hide();
123 |
124 | /**
125 | * Show the system UI.
126 | */
127 | public abstract void show();
128 |
129 | /**
130 | * Toggle the visibility of the system UI.
131 | */
132 | public void toggle() {
133 | if (isVisible()) {
134 | hide();
135 | } else {
136 | show();
137 | }
138 | }
139 |
140 | /**
141 | * Registers a callback, to be triggered when the system UI visibility
142 | * changes.
143 | */
144 | public void setOnVisibilityChangeListener(OnVisibilityChangeListener listener) {
145 | if (listener == null) {
146 | listener = sDummyListener;
147 | }
148 |
149 | mOnVisibilityChangeListener = listener;
150 | }
151 |
152 | /**
153 | * A dummy no-op callback for use when there is no other listener set.
154 | */
155 | private static OnVisibilityChangeListener sDummyListener = new OnVisibilityChangeListener() {
156 | @Override
157 | public void onVisibilityChange(boolean visible) {
158 | }
159 | };
160 |
161 | /**
162 | * A callback interface used to listen for system UI visibility changes.
163 | */
164 | public interface OnVisibilityChangeListener {
165 | /**
166 | * Called when the system UI visibility has changed.
167 | *
168 | * @param visible True if the system UI is visible.
169 | */
170 | public void onVisibilityChange(boolean visible);
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/api/Movie4kParser.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.api;
2 |
3 | import android.util.SparseArray;
4 |
5 | import com.ov3rk1ll.kinocast.R;
6 | import com.ov3rk1ll.kinocast.api.mirror.Host;
7 | import com.ov3rk1ll.kinocast.data.ViewModel;
8 | import com.ov3rk1ll.kinocast.ui.DetailActivity;
9 | import com.ov3rk1ll.kinocast.utils.Utils;
10 |
11 | import org.jsoup.Jsoup;
12 | import org.jsoup.nodes.Document;
13 | import org.jsoup.nodes.Element;
14 | import org.jsoup.select.Elements;
15 |
16 | import java.io.IOException;
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | public class Movie4kParser extends Parser{
21 | public static final int PARSER_ID = 1;
22 | public static final String URL_BASE = "http://www.movie4k.tv/";
23 |
24 | private static final SparseArray languageResMap = new SparseArray();
25 | private static final SparseArray languageKeyMap = new SparseArray();
26 | static {
27 | languageResMap.put(1, R.drawable.lang_de); languageKeyMap.put(1, "de");
28 | languageResMap.put(2, R.drawable.lang_en); languageKeyMap.put(2, "de");
29 | languageResMap.put(4, R.drawable.lang_zh); languageKeyMap.put(4, "zh");
30 | languageResMap.put(5, R.drawable.lang_es); languageKeyMap.put(5, "es");
31 | languageResMap.put(6, R.drawable.lang_fr); languageKeyMap.put(6, "fr");
32 | languageResMap.put(7, R.drawable.lang_tr); languageKeyMap.put(7, "tr");
33 | languageResMap.put(8, R.drawable.lang_jp); languageKeyMap.put(8, "jp");
34 | languageResMap.put(9, R.drawable.lang_ar); languageKeyMap.put(9, "ar");
35 | languageResMap.put(11, R.drawable.lang_it); languageKeyMap.put(11, "it");
36 | languageResMap.put(12, R.drawable.lang_hr); languageKeyMap.put(12, "hr");
37 | languageResMap.put(13, R.drawable.lang_sr); languageKeyMap.put(13, "sr");
38 | languageResMap.put(14, R.drawable.lang_bs); languageKeyMap.put(14, "bs");
39 | languageResMap.put(15, R.drawable.lang_de_en); languageKeyMap.put(15, "en");
40 | languageResMap.put(16, R.drawable.lang_nl); languageKeyMap.put(16, "nl");
41 | languageResMap.put(17, R.drawable.lang_ko); languageKeyMap.put(17, "ko");
42 | languageResMap.put(24, R.drawable.lang_el); languageKeyMap.put(24, "el");
43 | languageResMap.put(25, R.drawable.lang_ru); languageKeyMap.put(25, "ru");
44 | languageResMap.put(26, R.drawable.lang_hi); languageKeyMap.put(26, "hi");
45 | }
46 |
47 | public Movie4kParser(String url) {
48 | super(url);
49 | }
50 |
51 | @Override
52 | public String getParserName() {
53 | return "Movie4k";
54 | }
55 |
56 | @Override
57 | public int getParserId(){
58 | return PARSER_ID;
59 | }
60 |
61 | private List parseList(Document doc){
62 | List list = new ArrayList();
63 | Elements files = doc.select("div#maincontentnew");
64 | for(Element file : files){
65 | ViewModel model = new ViewModel();
66 |
67 | Elements divs = file.select("div");
68 | Element data = divs.get(2);
69 | model.setSlug(data.select("h2 > a").attr("href"));
70 | model.setTitle(data.select("h2 > a").text());
71 |
72 | Element more = file.select("div.beschreibung").first();
73 | }
74 | //TODO
75 | return list;
76 | }
77 |
78 | @Override
79 | public List parseList(String url){
80 | try {
81 | Document doc = Jsoup.connect(url)
82 | .userAgent(Utils.USER_AGENT)
83 | .timeout(10000)
84 | .get();
85 |
86 | return parseList(doc);
87 | } catch (IOException e) {
88 | e.printStackTrace();
89 | }
90 | return null;
91 | }
92 |
93 | private ViewModel parseDetail(Document doc, ViewModel item){
94 | // TODO
95 | return item;
96 | }
97 |
98 | @Override
99 | public ViewModel loadDetail(ViewModel item){
100 | try {
101 | Document doc = Jsoup.connect(URL_BASE + "Stream/" + item.getSlug() + ".html")
102 | .userAgent(Utils.USER_AGENT)
103 | .cookie("StreamHostMirrorMode", "fixed")
104 | .cookie("StreamAutoHideMirrros", "Fixed")
105 | .cookie("StreamShowFacebook", "N")
106 | .cookie("StreamCommentLimit", "0")
107 | .cookie("StreamMirrorMode", "fixed")
108 | .timeout(10000)
109 | .get();
110 |
111 | return parseDetail(doc, item);
112 | } catch (IOException e) {
113 | e.printStackTrace();
114 | }
115 | return item;
116 | }
117 |
118 | @Override
119 | public ViewModel loadDetail(String url) {
120 | //TODO
121 | return null;
122 | }
123 |
124 | @Override
125 | public List getHosterList(ViewModel item, int season, String episode){
126 | //TODO
127 | return null;
128 | }
129 |
130 | @Override
131 | public String getMirrorLink(DetailActivity.QueryPlayTask queryTask, ViewModel item, int id, int mirror, int i, String url){
132 | //TODO
133 | return null;
134 | }
135 |
136 | @Override
137 | public String getMirrorLink(DetailActivity.QueryPlayTask queryPlayTask, ViewModel item, int hoster, int mirror){
138 | //TODO
139 | return null;
140 | }
141 |
142 | @Override
143 | public String[] getSearchSuggestions(String query){
144 | //TODO
145 | return null;
146 | }
147 |
148 | @Override
149 | public String getPageLink(ViewModel item){
150 | //TODO
151 | return null;
152 | }
153 |
154 | @Override
155 | public String getSearchPage(String query){
156 | //TODO
157 | return null;
158 | }
159 |
160 | @Override
161 | public String getCineMovies(){
162 | return URL_BASE + "index.php";
163 | }
164 |
165 | @Override
166 | public String getPopularMovies(){
167 | return URL_BASE + "Popular-Movies.html";
168 | }
169 |
170 | @Override
171 | public String getLatestMovies(){
172 | return URL_BASE + "Latest-Movies.html";
173 | }
174 |
175 | @Override
176 | public String getPopularSeries(){
177 | return URL_BASE + "Popular-Series.html";
178 | }
179 |
180 | @Override
181 | public String getLatestSeries(){
182 | return URL_BASE + "Latest-Series.html";
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/utils/TheMovieDb.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.utils;
2 |
3 | import android.content.Context;
4 |
5 | import com.ov3rk1ll.kinocast.api.Parser;
6 | import com.ov3rk1ll.kinocast.data.ViewModel;
7 |
8 | import org.json.JSONException;
9 | import org.json.JSONObject;
10 |
11 | import java.io.BufferedReader;
12 | import java.io.File;
13 | import java.io.FileInputStream;
14 | import java.io.FileOutputStream;
15 | import java.io.IOException;
16 | import java.io.InputStreamReader;
17 | import java.lang.ref.SoftReference;
18 | import java.util.concurrent.ConcurrentHashMap;
19 | import java.util.concurrent.ExecutorService;
20 | import java.util.concurrent.Executors;
21 |
22 | public class TheMovieDb {
23 | public static final String IMAGE_BASE_PATH = "http://image.tmdb.org/t/p/";
24 | private static final String DISK_CACHE_PATH = "/themoviedb_cache/";
25 | private static final String API_KEY = "f9dc7e5d12b2640bf4ef1cf20835a1cc";
26 |
27 | private ConcurrentHashMap> memoryCache;
28 | private String diskCachePath;
29 | private boolean diskCacheEnabled = false;
30 | private ExecutorService writeThread;
31 |
32 |
33 | public TheMovieDb(Context context) {
34 | // Set up in-memory cache store
35 | memoryCache = new ConcurrentHashMap<>();
36 |
37 | // Set up disk cache store
38 | Context appContext = context.getApplicationContext();
39 | diskCachePath = appContext.getCacheDir().getAbsolutePath() + DISK_CACHE_PATH;
40 |
41 | File outFile = new File(diskCachePath);
42 | outFile.mkdirs();
43 |
44 | diskCacheEnabled = outFile.exists();
45 |
46 | // Set up threadpool for image fetching tasks
47 | writeThread = Executors.newSingleThreadExecutor();
48 | }
49 |
50 | public JSONObject get(String url) {
51 | return get(url, true);
52 | }
53 |
54 | public JSONObject get(String url, boolean fetchIfNeeded) {
55 | JSONObject json;
56 | //String url = request.getUrl();
57 |
58 | // Check for image in memory
59 | json = getFromMemory(url);
60 |
61 | // Check for image on disk cache
62 | if(json == null) {
63 | json = getFromDisk(url);
64 |
65 | // Write bitmap back into memory cache
66 | if(json != null) {
67 | cacheToMemory(url, json);
68 | }
69 | }
70 | if(json == null || fetchIfNeeded) {
71 | try {
72 | // Get IMDB-ID from page
73 | ViewModel item = Parser.getInstance().loadDetail(url);
74 | String param = url.substring(url.indexOf("#") + 1);
75 | // tt1646971?api_key=f9dc7e5d12b2640bf4ef1cf20835a1cc&language=de&external_source=imdb_id
76 | JSONObject data = Utils.readJson("http://api.themoviedb.org/3/find/" + item.getImdbId() + "?api_key=" + API_KEY + "&external_source=imdb_id&" + param);
77 | if(data == null) return null;
78 | if(data.getJSONArray("movie_results").length() > 0) {
79 | json = data.getJSONArray("movie_results").getJSONObject(0);
80 | }else if(data.getJSONArray("tv_results").length() > 0) {
81 | json = data.getJSONArray("tv_results").getJSONObject(0);
82 | }
83 | if(json != null) {
84 | put(url, json);
85 | }
86 | } catch (JSONException e) {
87 | e.printStackTrace();
88 | }
89 | }
90 |
91 | return json;
92 | }
93 |
94 | private void put(String url, JSONObject json) {
95 | cacheToMemory(url, json);
96 | cacheToDisk(url, json);
97 | }
98 |
99 | private JSONObject getFromMemory(String url) {
100 | JSONObject json = null;
101 | SoftReference softRef = memoryCache.get(getCacheKey(url));
102 | if(softRef != null){
103 | json = softRef.get();
104 | }
105 |
106 | return json;
107 | }
108 |
109 | private JSONObject getFromDisk(String url) {
110 | JSONObject json = null;
111 | if(diskCacheEnabled){
112 | String filePath = getFilePath(url);
113 | File file = new File(filePath);
114 | if(file.exists()) {
115 | try {
116 | BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
117 | StringBuilder content = new StringBuilder();
118 | char[] buffer = new char[1024];
119 | int num;
120 | while ((num = input.read(buffer)) > 0) {
121 | content.append(buffer, 0, num);
122 | }
123 | json = new JSONObject(content.toString());
124 | } catch (JSONException | IOException e) {
125 | e.printStackTrace();
126 | }
127 |
128 | }
129 | }
130 | return json;
131 | }
132 |
133 | private void cacheToMemory(final String url, final JSONObject json) {
134 | memoryCache.put(getCacheKey(url), new SoftReference<>(json));
135 | }
136 |
137 | private void cacheToDisk(final String url, final JSONObject json) {
138 | writeThread.execute(new Runnable() {
139 | @Override
140 | public void run() {
141 | if(diskCacheEnabled) {
142 | FileOutputStream ostream = null;
143 | try {
144 | ostream = new FileOutputStream(new File(diskCachePath, getCacheKey(url)));
145 | ostream.write(json.toString().getBytes());
146 | } catch (IOException e) {
147 | e.printStackTrace();
148 | } finally {
149 | try {
150 | if(ostream != null) {
151 | ostream.flush();
152 | ostream.close();
153 | }
154 | } catch (IOException ignored) {}
155 | }
156 | }
157 | }
158 | });
159 | }
160 |
161 | private String getFilePath(String url) {
162 | return diskCachePath + getCacheKey(url);
163 | }
164 |
165 | private String getCacheKey(String url) {
166 | if(url == null){
167 | throw new RuntimeException("Null url passed in");
168 | } else {
169 | if(url.contains("#"))
170 | url = url.substring(0, url.indexOf("#"));
171 | return url.replaceAll("[.:/,%?&=]", "+").replaceAll("[+]+", "+");
172 | }
173 | }
174 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/ui/OrderHostlistActivity.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.ui;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.SharedPreferences;
5 | import android.os.Bundle;
6 | import android.preference.PreferenceManager;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.Toolbar;
10 | import android.util.SparseIntArray;
11 | import android.view.LayoutInflater;
12 | import android.view.MenuItem;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.widget.ImageView;
16 | import android.widget.TextView;
17 | import android.widget.Toast;
18 |
19 | import com.ov3rk1ll.kinocast.R;
20 | import com.ov3rk1ll.kinocast.api.mirror.Host;
21 | import com.ov3rk1ll.kinocast.utils.Utils;
22 | import com.woxthebox.draglistview.DragItemAdapter;
23 | import com.woxthebox.draglistview.DragListView;
24 |
25 | import java.util.ArrayList;
26 | import java.util.Collections;
27 | import java.util.Comparator;
28 |
29 | public class OrderHostlistActivity extends AppCompatActivity {
30 | private ArrayList- mItemArray;
31 | SparseIntArray sortedList = new SparseIntArray();
32 |
33 | @Override
34 | protected void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 | setContentView(R.layout.activity_order_hostlist);
37 |
38 | Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar_actionbar);
39 | setSupportActionBar(toolbar);
40 | if(getSupportActionBar() != null) {
41 | getSupportActionBar().setHomeButtonEnabled(true);
42 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
43 | }
44 |
45 | DragListView mDragListView = (DragListView) findViewById(R.id.drag_list_view);
46 | mDragListView.getRecyclerView().setVerticalScrollBarEnabled(true);
47 |
48 | mItemArray = new ArrayList<>();
49 | for (Class> h: Host.HOSTER_LIST) {
50 | try {
51 | Host host = (Host) h.getConstructor().newInstance();
52 | if(host.isEnabled()) {
53 | mItemArray.add(new Item(host.getId(), host.getName(), R.drawable.ic_drag_handle_black_48dp));
54 | }
55 | } catch (Exception e) {
56 | e.printStackTrace();
57 | }
58 | }
59 |
60 | sortedList = Utils.getWeightedHostList(getApplicationContext());
61 | if(sortedList != null) {
62 | Collections.sort(mItemArray, new Comparator
- () {
63 | @Override
64 | public int compare(Item o1, Item o2) {
65 | int x = sortedList.get(o1.getId(), o1.getId());
66 | int y = sortedList.get(o2.getId(), o1.getId());
67 | return (x < y) ? -1 : ((x == y) ? 0 : 1);
68 | }
69 | });
70 | }
71 |
72 | mDragListView.setLayoutManager(new LinearLayoutManager(this));
73 | ItemAdapter listAdapter = new ItemAdapter(mItemArray, R.layout.order_hostlist_item, R.id.image, false);
74 | mDragListView.setAdapter(listAdapter, true);
75 | mDragListView.setCanDragHorizontally(false);
76 | }
77 |
78 | @SuppressLint("ApplySharedPref")
79 | @Override
80 | protected void onPause() {
81 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
82 | SharedPreferences.Editor editor = preferences.edit();
83 | for(int i = 0; i < mItemArray.size(); i++){
84 | editor.putInt("order_hostlist_" + i, mItemArray.get(i).getId());
85 | }
86 | editor.putInt("order_hostlist_count", mItemArray.size());
87 | editor.commit();
88 | super.onPause();
89 | }
90 |
91 | @Override
92 | public boolean onOptionsItemSelected(MenuItem item) {
93 | int id = item.getItemId();
94 | if (id == android.R.id.home) {
95 | supportFinishAfterTransition();
96 | return true;
97 | }
98 | return super.onOptionsItemSelected(item);
99 | }
100 |
101 | static class Item{
102 | private int id;
103 | private String name;
104 | private int resId;
105 |
106 | Item(int id, String name, int resId) {
107 | this.id = id;
108 | this.name = name;
109 | this.resId = resId;
110 | }
111 |
112 | public int getId() {
113 | return id;
114 | }
115 |
116 | public String getName() {
117 | return name;
118 | }
119 |
120 | int getResId() {
121 | return resId;
122 | }
123 |
124 | @Override
125 | public String toString() {
126 | return "Item {id = " + id + ", name = " + name + "}";
127 | }
128 | }
129 |
130 | static class ItemAdapter extends DragItemAdapter
- {
131 |
132 | private int mLayoutId;
133 | private int mGrabHandleId;
134 |
135 | ItemAdapter(ArrayList
- list, int layoutId, int grabHandleId, boolean dragOnLongPress) {
136 | super(dragOnLongPress);
137 | mLayoutId = layoutId;
138 | mGrabHandleId = grabHandleId;
139 | setHasStableIds(true);
140 | setItemList(list);
141 | }
142 |
143 | @Override
144 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
145 | View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);
146 | return new ViewHolder(view);
147 | }
148 |
149 | @Override
150 | public void onBindViewHolder(ViewHolder holder, int position) {
151 | super.onBindViewHolder(holder, position);
152 | String text = mItemList.get(position).getName();
153 | holder.mText.setText(text);
154 | holder.itemView.setTag(text);
155 | holder.mImage.setImageResource(mItemList.get(position).getResId());
156 | }
157 |
158 | @Override
159 | public long getItemId(int position) {
160 | return mItemList.get(position).getId();
161 | }
162 |
163 | class ViewHolder extends DragItemAdapter
- .ViewHolder {
164 | TextView mText;
165 | ImageView mImage;
166 |
167 | ViewHolder(final View itemView) {
168 | super(itemView, mGrabHandleId);
169 | mText = (TextView) itemView.findViewById(R.id.text);
170 | mImage = (ImageView) itemView.findViewById(R.id.image);
171 | }
172 |
173 | @Override
174 | public void onItemClicked(View view) {
175 | Toast.makeText(view.getContext(), "Item clicked", Toast.LENGTH_SHORT).show();
176 | }
177 |
178 | @Override
179 | public boolean onItemLongClicked(View view) {
180 | Toast.makeText(view.getContext(), "Item long clicked", Toast.LENGTH_SHORT).show();
181 | return true;
182 | }
183 | }
184 | }
185 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/ui/helper/layout/GridLayoutManager.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.ui.helper.layout;
2 |
3 |
4 | import android.content.Context;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.Log;
7 | import android.view.View;
8 |
9 | public class GridLayoutManager extends BaseLayoutManager {
10 |
11 | private static final int DEFAULT_COLUMNS = 2;
12 | private int columns;
13 |
14 | private static final String TAG = GridLayoutManager.class.getSimpleName();
15 |
16 | public GridLayoutManager(Context context){
17 | this(context, DEFAULT_COLUMNS, VERTICAL);
18 | }
19 |
20 | public GridLayoutManager(Context context, int columns, int orientation) {
21 | super(context, orientation, false);
22 | this.columns = columns;
23 | }
24 |
25 | public int getColumns() {
26 | return columns;
27 | }
28 |
29 | public void setColumns(int columns) {
30 | this.columns = columns;
31 | }
32 |
33 | @Override
34 | protected int fill(RecyclerView.Recycler recycler, BaseLayoutManager.RenderState renderState,
35 | RecyclerView.State state, boolean stopOnFocusable) {
36 | int itemWidth;
37 | if (mOrientation == VERTICAL) {
38 | itemWidth = (getWidth() - getPaddingLeft() - getPaddingRight()) / columns;
39 | }else{
40 | itemWidth = (getHeight() - getPaddingTop() - getPaddingBottom()) / columns;
41 | }
42 | // max offset we should set is mFastScroll + available
43 | final int start = renderState.mAvailable;
44 | if (renderState.mScrollingOffset != RenderState.SCOLLING_OFFSET_NaN) {
45 | // TODO ugly bug fix. should not happen
46 | if (renderState.mAvailable < 0) {
47 | renderState.mScrollingOffset += renderState.mAvailable;
48 | }
49 | recycleByRenderState(recycler, renderState);
50 | }
51 | int remainingSpace = renderState.mAvailable + renderState.mExtra;
52 | int columnCount = 0;
53 | while (remainingSpace > 0 && renderState.hasMore(state)) {
54 | View view = renderState.next(recycler);
55 | if (view == null) {
56 | if (DEBUG && renderState.mScrapList == null) {
57 | throw new RuntimeException("received null view when unexpected");
58 | }
59 | // if we are laying out views in scrap, this may return null which means there is
60 | // no more items to layout.
61 | break;
62 | }
63 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
64 | if (!params.isItemRemoved() && mRenderState.mScrapList == null) {
65 | if (mShouldReverseLayout == (renderState.mLayoutDirection
66 | == RenderState.LAYOUT_START)) {
67 | addView(view);
68 | } else {
69 | addView(view, 0);
70 | }
71 | }
72 |
73 | if (mOrientation == VERTICAL) {
74 | params.width = itemWidth - params.leftMargin - params.rightMargin;
75 | }else{
76 | params.height = itemWidth - params.topMargin - params.bottomMargin;
77 | }
78 | measureChildWithMargins(view, 0, 0);
79 | int consumed = mOrientationHelper.getDecoratedMeasurement(view);
80 | int left, top, right, bottom;
81 | if (mOrientation == VERTICAL) {
82 | if (isLayoutRTL() == (renderState.mLayoutDirection
83 | == RenderState.LAYOUT_END)) {
84 | right = getWidth() - getPaddingRight() - itemWidth * columnCount;
85 | left = right - mOrientationHelper.getDecoratedMeasurementInOther(view);
86 | } else {
87 | left = columnCount * itemWidth + getPaddingLeft();
88 | right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
89 | }
90 | if (renderState.mLayoutDirection == RenderState.LAYOUT_START) {
91 | bottom = renderState.mOffset;
92 | top = renderState.mOffset - consumed;
93 | } else {
94 | top = renderState.mOffset;
95 | bottom = renderState.mOffset + consumed;
96 | }
97 | } else {
98 | if (renderState.mLayoutDirection == RenderState.LAYOUT_START) {
99 | bottom = getHeight() - getPaddingBottom() - itemWidth * columnCount;
100 | top = bottom - mOrientationHelper.getDecoratedMeasurementInOther(view);
101 | right = renderState.mOffset;
102 | left = renderState.mOffset - consumed;
103 | } else {
104 | top = columnCount * itemWidth + getPaddingTop();
105 | bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
106 | left = renderState.mOffset;
107 | right = renderState.mOffset + consumed;
108 | }
109 | }
110 | // We calculate everything with View's bounding box (which includes decor and margins)
111 | // To calculate correct layout position, we subtract margins.
112 | layoutDecorated(view, left + params.leftMargin, top + params.topMargin
113 | , right - params.rightMargin, bottom - params.bottomMargin);
114 | if (DEBUG) {
115 | Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:"
116 | + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:"
117 | + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin));
118 | }
119 |
120 | if (!params.isItemRemoved()) {
121 | columnCount++;
122 | if (columnCount == columns) {
123 | columnCount = 0;
124 | renderState.mOffset += consumed * renderState.mLayoutDirection;
125 | renderState.mAvailable -= consumed;
126 | // we keep a separate remaining space because mAvailable is important for recycling
127 | remainingSpace -= consumed;
128 |
129 | if (renderState.mScrollingOffset != RenderState.SCOLLING_OFFSET_NaN) {
130 | renderState.mScrollingOffset += consumed;
131 | if (renderState.mAvailable < 0) {
132 | renderState.mScrollingOffset += renderState.mAvailable;
133 | }
134 | recycleByRenderState(recycler, renderState);
135 | }
136 | }
137 | }
138 |
139 | if (stopOnFocusable && view.isFocusable()) {
140 | break;
141 | }
142 |
143 | if (state != null && state.getTargetScrollPosition() == getPosition(view)) {
144 | break;
145 | }
146 | }
147 | if (DEBUG) {
148 | validateChildOrder();
149 | }
150 | return start - renderState.mAvailable;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/api/Parser.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.api;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 | import android.text.TextUtils;
7 | import android.util.Log;
8 |
9 | import com.ov3rk1ll.kinocast.R;
10 | import com.ov3rk1ll.kinocast.api.mirror.Host;
11 | import com.ov3rk1ll.kinocast.data.ViewModel;
12 | import com.ov3rk1ll.kinocast.ui.DetailActivity;
13 | import com.ov3rk1ll.kinocast.utils.CloudflareDdosInterceptor;
14 | import com.ov3rk1ll.kinocast.utils.CustomDns;
15 | import com.ov3rk1ll.kinocast.utils.InjectedCookieJar;
16 | import com.ov3rk1ll.kinocast.utils.UserAgentInterceptor;
17 | import com.ov3rk1ll.kinocast.utils.Utils;
18 |
19 | import org.json.JSONException;
20 | import org.json.JSONObject;
21 | import org.jsoup.Jsoup;
22 | import org.jsoup.nodes.Document;
23 |
24 | import java.io.IOException;
25 | import java.util.List;
26 | import java.util.Map;
27 |
28 | import okhttp3.Cookie;
29 | import okhttp3.OkHttpClient;
30 | import okhttp3.Request;
31 | import okhttp3.Response;
32 |
33 | public abstract class Parser {
34 | private static final String TAG = Parser.class.getSimpleName();
35 | private static final int PARSER_ID = -1;
36 | String URL_BASE;
37 | private static OkHttpClient client;
38 | private static InjectedCookieJar injectedCookieJar;
39 |
40 | private static Parser instance;
41 | public static Parser getInstance(){
42 | return instance;
43 | }
44 |
45 | public static void selectParser(Context context, int id){
46 | instance = selectByParserId(context, id);
47 | initHttpClient(context);
48 | }
49 | public static void selectParser(Context context, int id, String url){
50 | instance = selectByParserId(id, url);
51 | initHttpClient(context);
52 | }
53 | public static Parser selectByParserId(Context context, int id){
54 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
55 | String url = preferences.getString("url", context.getString(R.string.defaul_url));
56 | return selectByParserId(id, url);
57 | }
58 | private static Parser selectByParserId(int id, String url) {
59 | if (!url.endsWith("/")) url = url + "/";
60 | Log.i(TAG, "selectByParserId: load with #" + id + " for " + url);
61 | switch (id) {
62 | case KinoxParser.PARSER_ID:
63 | return new KinoxParser(url);
64 | case Movie4kParser.PARSER_ID:
65 | return new Movie4kParser(url);
66 | }
67 | return null;
68 | }
69 |
70 | private static void initHttpClient(Context context){
71 | injectedCookieJar = new InjectedCookieJar();
72 | client = new OkHttpClient.Builder()
73 | .followRedirects(false)
74 | .followSslRedirects(false)
75 | .addNetworkInterceptor(new UserAgentInterceptor(Utils.USER_AGENT))
76 | .addInterceptor(new CloudflareDdosInterceptor(context))
77 | .cookieJar(injectedCookieJar)
78 | .dns(new CustomDns())
79 | .build();
80 | }
81 |
82 | Document getDocument(String url) throws IOException {
83 | return getDocument(url, null);
84 | }
85 |
86 | Document getDocument(String url, Map cookies) throws IOException {
87 | Request request = new Request.Builder()
88 | .url(url)
89 | .build();
90 |
91 | if(cookies != null) {
92 | for (String key : cookies.keySet()) {
93 | injectedCookieJar.addCookie(new Cookie.Builder()
94 | .domain(request.url().host())
95 | .name(key)
96 | .value(cookies.get(key))
97 | .build()
98 | );
99 | }
100 | }
101 | Response response = client.newCall(request).execute();
102 | if(response.code() != 200){
103 | throw new IOException("Unexpected status code " + response.code());
104 | }
105 | String body = response.body().string();
106 | if(TextUtils.isEmpty(body)){
107 | throw new IOException("Body for " + url + " is empty");
108 | }
109 | return Jsoup.parse(body);
110 | }
111 |
112 | public String getBody(String url) {
113 | OkHttpClient noFollowClient = client.newBuilder().followRedirects(false).build();
114 | Request request = new Request.Builder().url(url).build();
115 | Log.i(TAG, "read text from " + url + ", cookies=" + noFollowClient.cookieJar().toString());
116 | try {
117 | Response response = noFollowClient.newCall(request).execute();
118 | Log.i(TAG, "Got " + response.code() + " for " + url + ", cookies=" + noFollowClient.cookieJar().toString());
119 | for(String key : response.headers().names()){
120 | Log.i(TAG, key + "=" + response.header(key));
121 | }
122 |
123 | return response.body().string();
124 | } catch (IOException e) {
125 | e.printStackTrace();
126 | }
127 | return null;
128 | }
129 |
130 |
131 | JSONObject getJson(String url) {
132 | Request request = new Request.Builder().url(url).build();
133 |
134 | Log.i("Utils", "read json from " + url);
135 | try {
136 | Response response = client.newCall(request).execute();
137 | return new JSONObject(response.body().string());
138 | } catch (IOException | JSONException e) {
139 | e.printStackTrace();
140 | }
141 | return null;
142 | }
143 |
144 | public Parser(String url) {
145 | this.URL_BASE = url;
146 | }
147 |
148 | public abstract String getParserName();
149 |
150 | public int getParserId(){
151 | return PARSER_ID;
152 | }
153 |
154 | public abstract List parseList(String url) throws IOException;
155 |
156 | public abstract ViewModel loadDetail(ViewModel item);
157 |
158 | public abstract ViewModel loadDetail(String url);
159 |
160 | public abstract List getHosterList(ViewModel item, int season, String episode);
161 |
162 | public abstract String getMirrorLink(DetailActivity.QueryPlayTask queryTask, ViewModel item, int hoster, int mirror);
163 |
164 | public abstract String getMirrorLink(DetailActivity.QueryPlayTask queryTask, ViewModel item, int hoster, int mirror, int season, String episode);
165 |
166 | public abstract String[] getSearchSuggestions(String query);
167 |
168 | public abstract String getPageLink(ViewModel item);
169 |
170 | public abstract String getSearchPage(String query);
171 |
172 | public abstract String getCineMovies();
173 |
174 | public abstract String getPopularMovies();
175 |
176 | public abstract String getLatestMovies();
177 |
178 | public abstract String getPopularSeries();
179 |
180 | public abstract String getLatestSeries();
181 |
182 | public String getUrl(){
183 | return URL_BASE;
184 | }
185 |
186 | @Override
187 | public String toString() {
188 | return getParserName();
189 | }
190 |
191 | public OkHttpClient getClient(){
192 | return client;
193 | }
194 |
195 | }
196 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/ui/helper/layout/ResultRecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.ui.helper.layout;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.support.v7.graphics.Palette;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.ImageView;
11 | import android.widget.ProgressBar;
12 | import android.widget.RatingBar;
13 | import android.widget.TextView;
14 |
15 | import com.bumptech.glide.Glide;
16 | import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;
17 | import com.bumptech.glide.load.resource.drawable.GlideDrawable;
18 | import com.bumptech.glide.request.RequestListener;
19 | import com.bumptech.glide.request.target.Target;
20 | import com.ov3rk1ll.kinocast.R;
21 | import com.ov3rk1ll.kinocast.data.ViewModel;
22 | import com.ov3rk1ll.kinocast.ui.helper.PaletteManager;
23 | import com.ov3rk1ll.kinocast.ui.util.glide.OkHttpViewModelUrlLoader;
24 | import com.ov3rk1ll.kinocast.ui.util.glide.ViewModelGlideRequest;
25 |
26 | import java.io.InputStream;
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | public class ResultRecyclerAdapter extends RecyclerView.Adapter implements View.OnClickListener {
31 |
32 | private Context context;
33 | private List items;
34 | private OnRecyclerViewItemClickListener itemClickListener;
35 | private int itemLayout;
36 |
37 | public ResultRecyclerAdapter(Context context, int itemLayout) {
38 | this.context = context;
39 | this.items = new ArrayList<>();
40 | this.itemLayout = itemLayout;
41 |
42 | Glide.get(context)
43 | .register(ViewModelGlideRequest.class, InputStream.class, new OkHttpViewModelUrlLoader.Factory());
44 | }
45 |
46 | @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
47 | View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false);
48 | v.setOnClickListener(this);
49 | return new ViewHolder(v);
50 | }
51 |
52 | @Override public void onBindViewHolder(final ViewHolder holder, int position) {
53 | final ViewModel item = items.get(position);
54 | holder.itemView.setTag(item);
55 | holder.title.setText(item.getTitle());
56 | holder.rating.setRating(item.getRating() / 2.0f);
57 | holder.detail.setText(item.getGenre());
58 | holder.language.setImageResource(item.getLanguageResId());
59 |
60 | int px = holder.image.getContext().getResources().getDimensionPixelSize(R.dimen.list_item_width);
61 |
62 | Glide.with(context)
63 | .load(new ViewModelGlideRequest(item, px, "poster"))
64 | .placeholder(R.drawable.ic_loading_placeholder)
65 | .listener(new RequestListener() {
66 | @Override
67 | public boolean onException(Exception e, ViewModelGlideRequest model, Target target, boolean isFirstResource) {
68 | return false;
69 | }
70 |
71 | @Override
72 | public boolean onResourceReady(GlideDrawable resource, ViewModelGlideRequest model, Target target, boolean isFromMemoryCache, boolean isFirstResource) {
73 | holder.updatePalette(((GlideBitmapDrawable) resource.getCurrent()).getBitmap());
74 | holder.image.setVisibility(View.VISIBLE);
75 | holder.progressBar.setVisibility(View.GONE);
76 | return false;
77 | }
78 | })
79 | .into(holder.image);
80 | holder.image.setVisibility(View.VISIBLE);
81 |
82 | /*holder.image.setImageItem(item.getImageRequest(px, "poster"), R.drawable.ic_loading_placeholder, new SmartImageTask.OnCompleteListener() {
83 | @Override
84 | public void onComplete() {
85 | holder.updatePalette();
86 | holder.image.setVisibility(View.VISIBLE);
87 | holder.progressBar.setVisibility(View.GONE);
88 | }
89 | });*/
90 | if(position == 1){
91 | holder.itemView.setSelected(true);
92 | }
93 |
94 | }
95 |
96 |
97 | @Override public int getItemCount() {
98 | return items.size();
99 | }
100 |
101 | @Override public void onClick(View view) {
102 | if (itemClickListener != null) {
103 | ViewModel model = (ViewModel) view.getTag();
104 | itemClickListener.onItemClick(view, model);
105 | }
106 | }
107 |
108 | public void add(ViewModel item, int position) {
109 | items.add(position, item);
110 | notifyItemInserted(position);
111 | }
112 |
113 | public void remove(ViewModel item) {
114 | int position = items.indexOf(item);
115 | items.remove(position);
116 | notifyItemRemoved(position);
117 | }
118 |
119 | public void setOnItemClickListener(OnRecyclerViewItemClickListener listener) {
120 | this.itemClickListener = listener;
121 | }
122 |
123 | private static int setColorAlpha(int color, int alpha) {
124 | return (alpha << 24) | (color & 0x00ffffff);
125 | }
126 |
127 | public ViewModel[] getItems() {
128 | return items.toArray(new ViewModel[items.size()]);
129 | }
130 |
131 | static class ViewHolder extends RecyclerView.ViewHolder {
132 | private View background;
133 | public ImageView image;
134 | public TextView title;
135 | public ImageView language;
136 | RatingBar rating;
137 | TextView detail;
138 | ProgressBar progressBar;
139 |
140 | ViewHolder(View itemView) {
141 | super(itemView);
142 | background = itemView.findViewById(R.id.layoutInfo);
143 | image = (ImageView) itemView.findViewById(R.id.image);
144 | title = (TextView) itemView.findViewById(R.id.title);
145 | language = (ImageView) itemView.findViewById(R.id.language);
146 | rating = (RatingBar) itemView.findViewById(R.id.rating);
147 | detail = (TextView) itemView.findViewById(R.id.detail);
148 | progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar);
149 | image.setVisibility(View.GONE);
150 | }
151 |
152 | void updatePalette(Bitmap bitmap) {
153 | final String key = ((ViewModel)itemView.getTag()).getSlug();
154 | PaletteManager.getInstance().getPalette(key, bitmap, new PaletteManager.Callback() {
155 | @Override
156 | public void onPaletteReady(Palette palette) {
157 | Palette.Swatch swatch = palette.getDarkVibrantSwatch();
158 | if(swatch != null) {
159 | background.setBackgroundColor(setColorAlpha(swatch.getRgb(), 192));
160 | title.setTextColor(swatch.getTitleTextColor());
161 | detail.setTextColor(swatch.getBodyTextColor());
162 | }
163 | }
164 | });
165 | }
166 |
167 |
168 | }
169 |
170 | public interface OnRecyclerViewItemClickListener {
171 | void onItemClick(View view, Model model);
172 | }
173 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ov3rk1ll/kinocast/ui/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.ov3rk1ll.kinocast.ui;
2 |
3 | import android.content.Intent;
4 | import android.content.SharedPreferences;
5 | import android.media.Ringtone;
6 | import android.media.RingtoneManager;
7 | import android.net.Uri;
8 | import android.os.Bundle;
9 | import android.preference.ListPreference;
10 | import android.preference.Preference;
11 | import android.preference.PreferenceFragment;
12 | import android.preference.PreferenceManager;
13 | import android.preference.RingtonePreference;
14 | import android.support.v4.app.NavUtils;
15 | import android.support.v7.app.AppCompatActivity;
16 | import android.text.TextUtils;
17 | import android.view.MenuItem;
18 | import android.widget.Toast;
19 |
20 | import com.ov3rk1ll.kinocast.BuildConfig;
21 | import com.ov3rk1ll.kinocast.R;
22 | import com.ov3rk1ll.kinocast.api.KinoxParser;
23 | import com.ov3rk1ll.kinocast.api.Parser;
24 | import com.winsontan520.wversionmanager.library.WVersionManager;
25 |
26 | public class SettingsActivity extends AppCompatActivity {
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | }
32 |
33 | @Override
34 | public boolean onOptionsItemSelected(MenuItem item) {
35 | int id = item.getItemId();
36 | if (id == android.R.id.home) {
37 | NavUtils.navigateUpFromSameTask(this);
38 | return true;
39 | }
40 | return super.onOptionsItemSelected(item);
41 | }
42 |
43 | @Override
44 | protected void onPostCreate(Bundle savedInstanceState) {
45 | super.onPostCreate(savedInstanceState);
46 | getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
47 | }
48 |
49 | public static class SettingsFragment extends PreferenceFragment {
50 | public void onCreate(Bundle savedInstanceState) {
51 | super.onCreate(savedInstanceState);
52 | setupSimplePreferencesScreen();
53 | }
54 |
55 | private void setupSimplePreferencesScreen() {
56 | // In the simplified UI, fragments are not used at all and we instead
57 | // use the older PreferenceActivity APIs.
58 |
59 | // Add 'general' preferences.
60 | addPreferencesFromResource(R.xml.pref_general);
61 |
62 |
63 | findPreference("order_hostlist").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
64 | @Override
65 | public boolean onPreferenceClick(Preference preference) {
66 | startActivity(new Intent(getActivity(), OrderHostlistActivity.class));
67 | return true;
68 | }
69 | });
70 | findPreference("version_information").setSummary("v" + BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")");
71 | findPreference("version_information").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
72 | @Override
73 | public boolean onPreferenceClick(Preference preference) {
74 | Toast.makeText(getActivity(), R.string.update_checking, Toast.LENGTH_SHORT).show();
75 | WVersionManager versionManager = new WVersionManager(getActivity());
76 | versionManager.setVersionContentUrl(getString(R.string.update_check));
77 | versionManager.setShowToastIfUpToDate(true);
78 | versionManager.checkVersion(true);
79 | return true;
80 | }
81 | });
82 |
83 | findPreference("donate").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
84 | @Override
85 | public boolean onPreferenceClick(Preference preference) {
86 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.paypal_donate)));
87 | startActivity(intent);
88 | return true;
89 | }
90 | });
91 |
92 | bindPreferenceSummaryToValue(findPreference("url"));
93 | findPreference("url").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
94 | @Override
95 | public boolean onPreferenceChange(Preference preference, Object o) {
96 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
97 | Parser.selectParser(getActivity(), preferences.getInt("parser", KinoxParser.PARSER_ID), o.toString());
98 | preference.setSummary(o.toString());
99 | return true;
100 | }
101 | });
102 |
103 | // Add 'notifications' preferences, and a corresponding header.
104 | /*PreferenceCategory fakeHeader = new PreferenceCategory(this);
105 | fakeHeader.setTitle(R.string.pref_header_notifications);
106 | getPreferenceScreen().addPreference(fakeHeader);
107 | addPreferencesFromResource(R.xml.pref_notification);*/
108 | }
109 |
110 | /**
111 | * A preference value change listener that updates the preference's summary
112 | * to reflect its new value.
113 | */
114 | private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
115 | @Override
116 | public boolean onPreferenceChange(Preference preference, Object value) {
117 | String stringValue = value.toString();
118 |
119 | if (preference instanceof ListPreference) {
120 | // For list preferences, look up the correct display value in
121 | // the preference's 'entries' list.
122 | ListPreference listPreference = (ListPreference) preference;
123 | int index = listPreference.findIndexOfValue(stringValue);
124 |
125 | // Set the summary to reflect the new value.
126 | preference.setSummary(
127 | index >= 0
128 | ? listPreference.getEntries()[index]
129 | : null);
130 |
131 | } else if (preference instanceof RingtonePreference) {
132 | // For ringtone preferences, look up the correct display value
133 | // using RingtoneManager.
134 | if (TextUtils.isEmpty(stringValue)) {
135 | // Empty values correspond to 'silent' (no ringtone).
136 | preference.setSummary(R.string.pref_ringtone_silent);
137 |
138 | } else {
139 | Ringtone ringtone = RingtoneManager.getRingtone(
140 | preference.getContext(), Uri.parse(stringValue));
141 |
142 | if (ringtone == null) {
143 | // Clear the summary if there was a lookup error.
144 | preference.setSummary(null);
145 | } else {
146 | // Set the summary to reflect the new ringtone display
147 | // name.
148 | String name = ringtone.getTitle(preference.getContext());
149 | preference.setSummary(name);
150 | }
151 | }
152 |
153 | } else {
154 | // For all other preferences, set the summary to the value's
155 | // simple string representation.
156 | preference.setSummary(stringValue);
157 | }
158 | return true;
159 | }
160 | };
161 |
162 | /**
163 | * Binds a preference's summary to its value. More specifically, when the
164 | * preference's value is changed, its summary (line of text below the
165 | * preference title) is updated to reflect the value. The summary is also
166 | * immediately updated upon calling this method. The exact display format is
167 | * dependent on the type of preference.
168 | *
169 | * @see #sBindPreferenceSummaryToValueListener
170 | */
171 | private static void bindPreferenceSummaryToValue(Preference preference) {
172 | // Set the listener to watch for value changes.
173 | preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
174 |
175 | // Trigger the listener immediately with the preference's
176 | // current value.
177 | sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
178 | PreferenceManager
179 | .getDefaultSharedPreferences(preference.getContext())
180 | .getString(preference.getKey(), ""));
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------