├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── gradle.xml
├── markdown-exported-files.xml
├── markdown-navigator.xml
├── markdown-navigator
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── .travis.yml
├── ISSUE_TEMPLATE.md
├── LICENSE.md
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── x1unix
│ │ └── avi
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── changelog_template.html
│ │ ├── help-en.html
│ │ ├── help-ru.html
│ │ ├── help-uk.html
│ │ ├── help.css
│ │ ├── hosts-rus.txt
│ │ ├── hosts.txt
│ │ └── urls.txt
│ ├── java
│ │ └── com
│ │ │ ├── kinopoisk
│ │ │ ├── Constants.java
│ │ │ ├── KinopoiskRequestInterceptor.java
│ │ │ └── NetworkApiFactory.java
│ │ │ └── x1unix
│ │ │ └── avi
│ │ │ ├── AppCompatPreferenceActivity.java
│ │ │ ├── Application.java
│ │ │ ├── ClickListener.java
│ │ │ ├── DashboardActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MovieDetailsActivity.java
│ │ │ ├── MoviePlayerActivity.java
│ │ │ ├── RecyclerTouchListener.java
│ │ │ ├── SearchActivity.java
│ │ │ ├── SearchWidgetProvider.java
│ │ │ ├── SettingsActivity.java
│ │ │ ├── SupportActivity.java
│ │ │ ├── UpdateDownloaderActivity.java
│ │ │ ├── adapter
│ │ │ ├── CachedMoviesListAdapter.java
│ │ │ └── MoviesAdapter.java
│ │ │ ├── dashboard
│ │ │ ├── DashboardFragmentPagerAdapter.java
│ │ │ ├── DashboardTabFragment.java
│ │ │ ├── FavoritesTabFragment.java
│ │ │ └── HistoryTabFragment.java
│ │ │ ├── helpers
│ │ │ ├── AdBlocker.java
│ │ │ ├── DownloadFileFromURL.java
│ │ │ └── PermissionHelper.java
│ │ │ ├── model
│ │ │ ├── AviSemVersion.java
│ │ │ ├── KPMovie.java
│ │ │ ├── KPMovieDetailViewResponse.java
│ │ │ ├── KPMovieItem.java
│ │ │ ├── KPMovieSearchResult.java
│ │ │ ├── KPPeople.java
│ │ │ ├── KPResponse.java
│ │ │ └── KPSearchResponse.java
│ │ │ ├── rest
│ │ │ ├── KPApiInterface.java
│ │ │ └── KPRestClient.java
│ │ │ ├── storage
│ │ │ ├── DBHelper.java
│ │ │ └── MoviesRepository.java
│ │ │ ├── updateManager
│ │ │ ├── BuildParser.java
│ │ │ ├── ISO8601.java
│ │ │ ├── OTARepoClientInterface.java
│ │ │ ├── OTARestClient.java
│ │ │ ├── OTAStateListener.java
│ │ │ └── OTAUpdateChecker.java
│ │ │ └── webplayer
│ │ │ ├── AviWebChromeClient.java
│ │ │ ├── AviWebView.java
│ │ │ └── AviWebViewClient.java
│ └── res
│ │ ├── drawable-v22
│ │ ├── ic_bookmark_full_wrapped.xml
│ │ └── ic_bookmark_wrapped.xml
│ │ ├── drawable
│ │ ├── avi_r.png
│ │ ├── avi_wide_r.png
│ │ ├── block_rounded.xml
│ │ ├── border_bottom.xml
│ │ ├── effect_ripple.xml
│ │ ├── ic_avi.xml
│ │ ├── ic_avi_wide.xml
│ │ ├── ic_bookmark.xml
│ │ ├── ic_bookmark_full.xml
│ │ ├── ic_bookmark_full_wrapped.xml
│ │ ├── ic_bookmark_gray.xml
│ │ ├── ic_bookmark_wrapped.xml
│ │ ├── ic_cloud_off_black.xml
│ │ ├── ic_error.xml
│ │ ├── ic_restore_gray.xml
│ │ ├── ic_search.xml
│ │ ├── ic_search_24dp.xml
│ │ ├── ic_search_gray.xml
│ │ ├── no_poster.png
│ │ ├── progress_drawable.xml
│ │ ├── splash_image.xml
│ │ └── star.xml
│ │ ├── layout-sw600dp-land
│ │ └── activity_movie_details.xml
│ │ ├── layout-sw600dp
│ │ └── list_item_movie.xml
│ │ ├── layout
│ │ ├── activity_dashboard.xml
│ │ ├── activity_main.xml
│ │ ├── activity_movie_details.xml
│ │ ├── activity_movie_player.xml
│ │ ├── activity_search.xml
│ │ ├── activity_settings.xml
│ │ ├── activity_support.xml
│ │ ├── activity_update_downloader.xml
│ │ ├── list_item_movie.xml
│ │ ├── tab_favorites.xml
│ │ ├── tab_history.xml
│ │ ├── view_loading_video.xml
│ │ └── widget_search.xml
│ │ ├── menu
│ │ ├── main_menu.xml
│ │ ├── menu_movie_details.xml
│ │ └── search_menu.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-land
│ │ └── dimens.xml
│ │ ├── values-port-v21
│ │ └── dimens.xml
│ │ ├── values-ru
│ │ └── strings.xml
│ │ ├── values-sw600dp-land
│ │ └── props.xml
│ │ ├── values-sw600dp
│ │ └── props.xml
│ │ ├── values-sw720dp-land
│ │ ├── dimens.xml
│ │ └── props.xml
│ │ ├── values-sw720dp
│ │ └── dimens.xml
│ │ ├── values-uk
│ │ └── strings.xml
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ ├── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── keys.xml
│ │ ├── props.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ ├── xml-v14
│ │ └── pref_main.xml
│ │ └── xml
│ │ ├── pref_main.xml
│ │ ├── search_widget_provider.xml
│ │ └── searchable.xml
│ └── test
│ └── java
│ └── com
│ └── x1unix
│ └── avi
│ └── ExampleUnitTest.java
├── build.gradle
├── deploy.sh
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/markdown-exported-files.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk8
3 | android:
4 | components:
5 | # Uncomment the lines below if you want to
6 | # use the latest revision of Android SDK Tools
7 | - tools
8 | - tools
9 | - platform-tools
10 | - add-on
11 | - extra
12 |
13 | # The BuildTools version used by your project
14 | - build-tools-24.0.3
15 |
16 | # The SDK version used to compile your project
17 | - android-24
18 |
19 | # Additional components
20 | - extra-google-google_play_services
21 | - extra-google-m2repository
22 | - extra-android-m2repository
23 | - addon-google_apis-google-19
24 |
25 | # Specify at least one system image,
26 | # if you need to run emulator(s) during your tests
27 | - sys-img-armeabi-v7a-android-24
28 | # - sys-img-x86-android-23
29 | licenses:
30 | - 'android-sdk-preview-license-.+'
31 | - 'android-sdk-license-.+'
32 | - 'google-gdk-license-.+'
33 | sudo: required
34 | after_failure: "cat $TRAVIS_BUILD_DIR/app/build/outputs/lint-results-debug.xml"
35 | after_success:
36 | - ./deploy.sh
37 | script:
38 | - ./gradlew assemble lint
39 | # after_script:
40 | # - echo no | android create avd --force -n test -t android-24 --abi armeabi-v7a
41 | # - emulator -avd test -no-skin -no-audio -no-window &
42 | # - android-wait-for-emulator
43 | # - adb shell input keyevent 82 &
44 | # - ./gradlew connectedCheck
45 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Environment
2 | **App Version:** Version of Avi related to the issue
3 |
4 | **Device:** Type your device name and model (for ex. Samsung Galaxy S2 GT-9100)
5 |
6 | **Android Version:** Your Android verision + ROM name if it's not stock.
7 |
8 | ## Description
9 | Describe short issue description
10 |
11 | ### Steps
12 | Describe your actions step by step.
13 |
14 | ### Result
15 | Describe received behavior
16 |
17 |
18 | ### Expected
19 | Describe expected result or behavior
20 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2016-present, Denis Sedchenko
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Avi
2 |
3 | [](https://travis-ci.org/odin3/Avi)
4 |
5 | Application that allows to watch movies online from any Android device.
6 |
7 | ## How it works
8 | This application uses internal KinoPoisk API to search, identify and collect data about the movie.
9 | To watch movies, I use [moonwalk.co](http://moonwalk.co/the_api) service that hosts movies and TV shows.
10 | Received Kinopoisk ID from movie used to get player's URL for the movie from Moonwalk.
11 |
12 | ## Requirements
13 | * Android 4.0+
14 | * Network connection
15 |
16 | ## Disclaimer
17 | Author doesn't take responsibillity for the video content. All data is hosted and provided by Moonwalk.
18 |
19 | ## Bug reports
20 | You can report a bug or propose a feature in [issues](https://github.com/odin3/Avi/issues) section.
21 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "24.0.3"
6 | defaultConfig {
7 | applicationId "com.x1unix.avi"
8 | minSdkVersion 14
9 | targetSdkVersion 24
10 | versionCode 20170319
11 | versionName "1.8.2"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | vectorDrawables {
14 | useSupportLibrary true
15 | }
16 | vectorDrawables.useSupportLibrary = true
17 | }
18 | lintOptions {
19 | abortOnError false
20 | }
21 | buildTypes {
22 | debug {
23 | debuggable true
24 | }
25 | release {
26 | debuggable false
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 |
32 | packagingOptions {
33 | exclude 'META-INF/LICENSE'
34 | }
35 | }
36 |
37 | dependencies {
38 | compile fileTree(dir: 'libs', include: ['*.jar'])
39 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
40 | exclude group: 'com.android.support', module: 'support-annotations'
41 | })
42 | compile 'com.android.support:appcompat-v7:24.2.1'
43 | compile 'com.google.code.gson:gson:2.6.2'
44 | compile 'com.squareup.retrofit2:retrofit:2.0.2'
45 | compile 'com.squareup.retrofit2:converter-gson:2.0.2'
46 | compile 'com.squareup.retrofit2:converter-jackson:2.0.2'
47 | compile 'com.android.support:recyclerview-v7:24.2.1'
48 | compile 'com.android.support:design:24.2.1'
49 | compile 'com.android.support:support-v4:24.2.1'
50 | compile 'com.android.support:support-vector-drawable:24.2.1'
51 | compile 'commons-codec:commons-codec:1.8'
52 | compile 'com.rollbar:rollbar-android:0.1.3'
53 | compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
54 | testCompile 'junit:junit:4.12'
55 | compile 'org.apache.commons:commons-lang3:3.5'
56 | compile 'com.android.support:cardview-v7:24.2.1'
57 | compile "com.squareup.okhttp3:okhttp-urlconnection:3.2.0"
58 |
59 | compile 'com.fasterxml.jackson.core:jackson-core:2.7.3'
60 | compile 'com.fasterxml.jackson.core:jackson-annotations:2.7.3'
61 | compile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
62 |
63 | compile 'com.github.bumptech.glide:glide:3.5.2'
64 |
65 | compile 'com.yandex.android:mobmetricalib:2.62'
66 | }
67 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\AppData\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/x1unix/avi/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.x1unix.avi", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
20 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
48 |
49 |
54 |
57 |
58 |
62 |
66 |
69 |
70 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/app/src/main/assets/changelog_template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Changelog
7 |
35 |
36 |
37 | %CONTENT%
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/assets/help-en.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Avi
6 |
7 |
8 |
9 |
10 |
11 | I have an issue when watching movies
12 |
13 | Try to do several steps:
14 |
15 | - Go to Settings
16 | - Uncheck Block ads parameter
17 | - Try to watch movie again
18 |
19 |
20 |
21 |
22 | Each search query returns 'not found' message
23 |
24 | This issue may appear when KinoPoisk's API is down or not available.
25 |
26 |
27 | Try to wait for an hour and retry search.
28 |
29 |
30 |
31 | How do I can update the app?
32 |
33 | You can check out for new updates at settings or at our repository.
34 |
35 |
36 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/assets/help-ru.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Avi
6 |
7 |
8 |
9 |
10 |
11 | У меня возникают проблемы при просмотре фильма
12 |
13 | Попробуйте следующее:
14 |
15 | - Зайдите в Настройки
16 | - Отключите параметр Блокировать рекламу
17 | - Попробуйте посмотреть фильм
18 |
19 |
20 |
21 |
22 | При любом поисковом запросе нету результатов
23 |
24 | Для поиска фильмов и сериалов, приложение использует API КиноПоиска.
25 |
26 |
27 | Если у вас случается подобная ситуация, это чаще всего означает что сервера, которые
28 | отвечают за работу API, временно не работают.
29 |
30 |
31 | Попробуйте подождать около часа и повторить поиск снова.
32 |
33 |
34 |
35 | Как я могу обновить приложение?
36 |
37 | Вы можете проверить обновления в настройках или на нашем репозитории.
38 |
39 |
40 |
41 | Я нашел ошибку. Куда мне сообщить?
42 |
43 | Отправляйте все найденые ошибки и предложения на баг-трекер
44 | или на avi-app@x1unix.com.
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/assets/help-uk.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Avi
6 |
7 |
8 |
9 |
10 |
11 | У мене виникають проблеми під час перегляду фільмів
12 |
13 | Спробуйте наступне:
14 |
15 | - Зайдіть у Налаштування
16 | - Відключить параметр Блокувати рекламу
17 | - Спробуйте знову подивитись фільм
18 |
19 |
20 |
21 |
22 | При будь-якому пошуковому запиті немає результатів
23 |
24 | Для пошуку фільмів і серіалів, додаток використовує API сервiсу "Кинопоиск".
25 |
26 |
27 | Якщо у вас трапляється подібна ситуація, це найчастіше означає що сервера, які
28 | відповідають за роботу API, тимчасово не працюють.
29 |
30 |
31 | Спробуйте почекати близько години і повторити пошук знову.
32 |
33 |
34 |
35 | Як я можу оновити аплікацію?
36 |
37 | Ви можете завантажувати оновлення через налаштування або з нашого репозиторію.
38 |
39 |
40 |
41 | Я знайшов помилку. Куди мені повідомити?
42 |
43 | Відсилайте усі знайдені помилки та пропозиціі на баг-трекер
44 | або на avi-app@x1unix.com.
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/assets/help.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin:0;
3 | padding:0;
4 | font: 10pt 'Roboto', sans-serif;
5 | }
6 |
7 | h1 {
8 | font-size: 14pt;
9 | color: white;
10 | background: #555;
11 | display: block;
12 | margin-top: 0;
13 | padding: 15px;
14 | }
15 |
16 | p {
17 | padding-left: 15px;
18 | padding-right: 15px;
19 | }
20 |
21 | section {
22 | padding-bottom: 32px;
23 | border-bottom: 1px solid #cecece;
24 | }
--------------------------------------------------------------------------------
/app/src/main/assets/urls.txt:
--------------------------------------------------------------------------------
1 | http://moonwalk.co/web/js/advertisment.js
2 | http://moonwalk.co/api/morefunc
3 | http://moonwalk.co/web/js/jquery_simpletip.js
--------------------------------------------------------------------------------
/app/src/main/java/com/kinopoisk/Constants.java:
--------------------------------------------------------------------------------
1 | package com.kinopoisk;
2 |
3 | public final class Constants {
4 | public static final String API_VERSION = "3.11.0";
5 | public static final String KINOPOISK_ENDPOINT = "https://ext.kinopoisk.ru/ios/";
6 | public static String getPosterUrl(String kpId) {
7 | return "http://st.kp.yandex.net/images/film_iphone/iphone360_" + kpId + ".jpg";
8 | }
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kinopoisk/KinopoiskRequestInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.kinopoisk;
2 |
3 | import java.io.IOException;
4 | import java.net.URL;
5 | import java.text.DateFormat;
6 | import java.text.SimpleDateFormat;
7 | import java.util.Date;
8 | import java.util.Locale;
9 |
10 | import org.apache.commons.codec.binary.Hex;
11 | import org.apache.commons.codec.digest.DigestUtils;
12 |
13 | import java.io.IOException;
14 | import java.net.URL;
15 | import java.text.DateFormat;
16 | import java.text.SimpleDateFormat;
17 | import java.util.Date;
18 | import java.util.Locale;
19 |
20 | import okhttp3.HttpUrl;
21 | import okhttp3.Interceptor;
22 | import okhttp3.Request;
23 | import okhttp3.Response;
24 |
25 |
26 | public class KinopoiskRequestInterceptor implements Interceptor {
27 |
28 | private static final String KP_SECRET = "a17qbcw1du0aedm";
29 | private static final String KP_UUID = "84e8b92499a32a3d0d8ea956e6a05d76";
30 | private static final String KP_CLIENT_ID = "55decdcf6d4cd1bcaa1b3856";
31 | private static final String API_CHECK_FOR_UPDATE = "ios/check-new-version.php";
32 |
33 | @Override
34 | public Response intercept(Chain chain) throws IOException {
35 |
36 | Request interceptedRequest = chain.request();
37 | HttpUrl originalHttpUrl = interceptedRequest.url();
38 |
39 | // chain.proceed(buildCheckForUpdateRequest(originalHttpUrl.host())).close();
40 | return chain.proceed(buildMainRequest(interceptedRequest));
41 | }
42 |
43 | private String encodeWithSecret(String action) {
44 | return new String(Hex.encodeHex(DigestUtils.md5(action + KP_SECRET)));
45 | }
46 |
47 | /** build main request with additional parameters, required by kinopoisk */
48 | private Request buildMainRequest(Request interceptedRequest) {
49 | HttpUrl interceptedUrl = interceptedRequest.url();
50 | String commandName = interceptedUrl.pathSegments().get(2);
51 | URL oUrl = interceptedUrl.url();
52 |
53 | String action;
54 | if (oUrl.getQuery() == null) {
55 | action = commandName + "?" + "uuid=" + KP_UUID;
56 | } else {
57 | action = commandName + "?" + oUrl.getQuery() + "&uuid=" + KP_UUID;
58 | }
59 |
60 | // Build encoded key for query
61 | String encodedKey = encodeWithSecret(action);
62 |
63 | // Put additional params to auth
64 | HttpUrl url = interceptedUrl.newBuilder()
65 | .addQueryParameter("uuid", KP_UUID)
66 | .addQueryParameter("key", encodedKey)
67 | .build();
68 |
69 | // Put additional headers to look like KP client
70 | interceptedRequest = basicHeaders(interceptedRequest.newBuilder()
71 | .removeHeader("User-Agent")
72 | .url(url))
73 | .build();
74 |
75 | return interceptedRequest;
76 | }
77 |
78 | /** build a request to check if our client is deprecated
79 | * with new kinopoisk api we should do it with any request to setup cookies */
80 | private Request buildCheckForUpdateRequest(String host) {
81 |
82 | String action = "check-new-version.php" + "?" + "appVersion=" + Constants.API_VERSION + "&uuid=" + KP_UUID;
83 | String encodedKey = encodeWithSecret(action);
84 |
85 | HttpUrl url = new HttpUrl.Builder()
86 | .scheme("https")
87 | .host(host)
88 | .addPathSegments(API_CHECK_FOR_UPDATE)
89 | .addQueryParameter("key", encodedKey)
90 | .addQueryParameter("appVersion", Constants.API_VERSION)
91 | .addQueryParameter("uuid", KP_UUID)
92 | .build();
93 |
94 | Request.Builder builder = basicHeaders(new Request.Builder())
95 | .url(url)
96 | .addHeader("Cookie", "user_country=ru");
97 |
98 | return builder.build();
99 | }
100 |
101 |
102 | private Request.Builder basicHeaders(Request.Builder builder) {
103 | // Generate req date
104 | Date date = new Date();
105 | DateFormat dateFormat = new SimpleDateFormat("HH:mm MM.dd.yyyy", Locale.getDefault());
106 | String clientDate = dateFormat.format(date);
107 |
108 | builder
109 | .addHeader("device", "android")
110 | .addHeader("Android-Api-Version", "22")
111 | .addHeader("countryID", "2")
112 | .addHeader("ClientId", KP_CLIENT_ID)
113 | .addHeader("clientDate", clientDate)
114 | .addHeader("cityID", "2")
115 | .addHeader("Image-Scale", "3")
116 | .addHeader("Cache-Control", "max-stale=0")
117 | .addHeader("User-Agent", "Android client (5.1 / api22), ru.kinopoisk/3.7.0 (45)")
118 | .addHeader("Accept-Encoding", "gzip");
119 |
120 | return builder;
121 | }
122 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kinopoisk/NetworkApiFactory.java:
--------------------------------------------------------------------------------
1 | package com.kinopoisk;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.core.Version;
5 | import com.fasterxml.jackson.databind.DeserializationFeature;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 | import com.fasterxml.jackson.databind.module.SimpleModule;
8 | import com.x1unix.avi.BuildConfig;
9 |
10 | import java.net.CookieManager;
11 | import java.net.CookiePolicy;
12 | import java.util.concurrent.TimeUnit;
13 |
14 | import okhttp3.Cache;
15 | import okhttp3.JavaNetCookieJar;
16 | import okhttp3.OkHttpClient;
17 | import okhttp3.logging.HttpLoggingInterceptor;
18 | import retrofit2.Retrofit;
19 | import retrofit2.converter.gson.GsonConverterFactory;
20 | import retrofit2.converter.jackson.JacksonConverterFactory;
21 |
22 | public class NetworkApiFactory {
23 |
24 | OkHttpClient provideHttpClient() {
25 | OkHttpClient.Builder builder = new OkHttpClient().newBuilder()
26 | .connectTimeout(30, TimeUnit.SECONDS);
27 |
28 |
29 | builder.addInterceptor(new KinopoiskRequestInterceptor());
30 |
31 | // Log http requests on debug
32 | if (BuildConfig.DEBUG) {
33 | //logging interceptor should be last interceptor in chain
34 | HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
35 | loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
36 |
37 | builder.addInterceptor(loggingInterceptor);
38 | }
39 |
40 | CookieManager cookieManager = new CookieManager();
41 | cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
42 | builder.cookieJar(new JavaNetCookieJar(cookieManager));
43 |
44 | return builder.build();
45 | }
46 |
47 | ObjectMapper provideObjectMapper() {
48 | final SimpleModule module = new SimpleModule("", Version.unknownVersion());
49 |
50 | //jackson object mapper setup
51 | ObjectMapper objectMapper = new ObjectMapper();
52 | objectMapper.registerModule(module);
53 | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
54 |
55 | // don not fail while unknown json props on release version
56 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
57 |
58 | return objectMapper;
59 | }
60 |
61 | JacksonConverterFactory provideJacksonConverterFactory(ObjectMapper objectMapper) {
62 | return JacksonConverterFactory.create(objectMapper);
63 | }
64 |
65 | public Retrofit getClient() {
66 | return new Retrofit.Builder()
67 | .baseUrl(Constants.KINOPOISK_ENDPOINT + Constants.API_VERSION + "/")
68 | .client(provideHttpClient())
69 | .addConverterFactory(GsonConverterFactory.create())
70 | .build();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/AppCompatPreferenceActivity.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import android.content.res.Configuration;
4 | import android.os.Bundle;
5 | import android.preference.PreferenceActivity;
6 | import android.support.annotation.LayoutRes;
7 | import android.support.annotation.Nullable;
8 | import android.support.v7.app.ActionBar;
9 | import android.support.v7.app.AppCompatDelegate;
10 | import android.support.v7.widget.Toolbar;
11 | import android.view.MenuInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | /**
16 | * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
17 | * to be used with AppCompat.
18 | */
19 | public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
20 |
21 | private AppCompatDelegate mDelegate;
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | getDelegate().installViewFactory();
26 | getDelegate().onCreate(savedInstanceState);
27 | super.onCreate(savedInstanceState);
28 | }
29 |
30 | @Override
31 | protected void onPostCreate(Bundle savedInstanceState) {
32 | super.onPostCreate(savedInstanceState);
33 | getDelegate().onPostCreate(savedInstanceState);
34 | }
35 |
36 | public ActionBar getSupportActionBar() {
37 | return getDelegate().getSupportActionBar();
38 | }
39 |
40 | public void setSupportActionBar(@Nullable Toolbar toolbar) {
41 | getDelegate().setSupportActionBar(toolbar);
42 | }
43 |
44 | @Override
45 | public MenuInflater getMenuInflater() {
46 | return getDelegate().getMenuInflater();
47 | }
48 |
49 | @Override
50 | public void setContentView(@LayoutRes int layoutResID) {
51 | getDelegate().setContentView(layoutResID);
52 | }
53 |
54 | @Override
55 | public void setContentView(View view) {
56 | getDelegate().setContentView(view);
57 | }
58 |
59 | @Override
60 | public void setContentView(View view, ViewGroup.LayoutParams params) {
61 | getDelegate().setContentView(view, params);
62 | }
63 |
64 | @Override
65 | public void addContentView(View view, ViewGroup.LayoutParams params) {
66 | getDelegate().addContentView(view, params);
67 | }
68 |
69 | @Override
70 | protected void onPostResume() {
71 | super.onPostResume();
72 | getDelegate().onPostResume();
73 | }
74 |
75 | @Override
76 | protected void onTitleChanged(CharSequence title, int color) {
77 | super.onTitleChanged(title, color);
78 | getDelegate().setTitle(title);
79 | }
80 |
81 | @Override
82 | public void onConfigurationChanged(Configuration newConfig) {
83 | super.onConfigurationChanged(newConfig);
84 | getDelegate().onConfigurationChanged(newConfig);
85 | }
86 |
87 | @Override
88 | protected void onStop() {
89 | super.onStop();
90 | getDelegate().onStop();
91 | }
92 |
93 | @Override
94 | protected void onDestroy() {
95 | super.onDestroy();
96 | getDelegate().onDestroy();
97 | }
98 |
99 | public void invalidateOptionsMenu() {
100 | getDelegate().invalidateOptionsMenu();
101 | }
102 |
103 | private AppCompatDelegate getDelegate() {
104 | if (mDelegate == null) {
105 | mDelegate = AppCompatDelegate.create(this, null);
106 | }
107 | return mDelegate;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/Application.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import android.os.Build;
4 | import android.support.v7.app.AppCompatDelegate;
5 |
6 | import com.yandex.metrica.YandexMetrica;
7 | public class Application extends android.app.Application {
8 | protected final String AM_KEY = "7968f25e-5d6b-4cb3-be18-069f2bf8bd8b";
9 |
10 | @Override
11 | public void onCreate() {
12 | super.onCreate();
13 |
14 | if (!BuildConfig.DEBUG) {
15 | // AppMetrica SDK
16 | YandexMetrica.activate(getApplicationContext(), AM_KEY);
17 | YandexMetrica.enableActivityAutoTracking(this);
18 |
19 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
20 | YandexMetrica.enableActivityAutoTracking(this);
21 | }
22 | }
23 | }
24 |
25 | static {
26 | AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/ClickListener.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import android.view.View;
4 |
5 | public interface ClickListener {
6 | void onClick(View view, int position);
7 |
8 | void onLongClick(View view, int position);
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/DashboardActivity.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import android.app.SearchManager;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.content.res.Configuration;
8 | import android.os.Build;
9 | import android.os.Handler;
10 | import android.preference.PreferenceManager;
11 | import android.support.design.widget.TabLayout;
12 | import android.support.v4.view.MenuItemCompat;
13 | import android.support.v4.view.ViewPager;
14 | import android.support.v7.app.ActionBar;
15 | import android.support.v7.app.AppCompatActivity;
16 | import android.os.Bundle;
17 | import android.support.v7.widget.SearchView;
18 | import android.support.v7.widget.Toolbar;
19 | import android.view.Menu;
20 | import android.view.MenuItem;
21 |
22 | import com.x1unix.avi.dashboard.*;
23 | import com.x1unix.avi.model.AviSemVersion;
24 | import com.x1unix.avi.storage.MoviesRepository;
25 | import com.x1unix.avi.updateManager.OTAStateListener;
26 | import com.x1unix.avi.updateManager.OTAUpdateChecker;
27 |
28 | public class DashboardActivity extends AppCompatActivity {
29 |
30 | private Toolbar toolbar;
31 |
32 | private MenuItem searchItem;
33 |
34 | // Menu items
35 | private MenuItem menuItemSettings;
36 | private MenuItem menuItemHelp;
37 | private DashboardFragmentPagerAdapter pageAdapter;
38 | private MoviesRepository moviesRepository;
39 |
40 | @Override
41 | protected void onCreate(Bundle savedInstanceState) {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.activity_dashboard);
44 |
45 | moviesRepository = MoviesRepository.getInstance(this);
46 |
47 | toolbar = (Toolbar) findViewById(R.id.toolbar);
48 | setSupportActionBar(toolbar);
49 | ActionBar actionBar = getSupportActionBar();
50 |
51 | // Get the ViewPager and set it's PagerAdapter so that it can display items
52 | ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
53 |
54 | pageAdapter = new DashboardFragmentPagerAdapter(getSupportFragmentManager(),
55 | DashboardActivity.this, moviesRepository);
56 | viewPager.setAdapter(pageAdapter);
57 |
58 | // Give the TabLayout the ViewPager
59 | TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
60 | tabLayout.setupWithViewPager(viewPager);
61 |
62 | // Init background updates check
63 | initBackgroundUpdateCheck();
64 | }
65 |
66 | @Override
67 | public void onRestart() {
68 | if (pageAdapter != null) {
69 | pageAdapter.triggerRescan();
70 | }
71 |
72 | super.onRestart();
73 | }
74 |
75 | @Override
76 | public void onConfigurationChanged(Configuration newConfig) {
77 | super.onConfigurationChanged(newConfig);
78 | pageAdapter.triggerUpdate();
79 | }
80 |
81 | @Override
82 | public boolean onCreateOptionsMenu(Menu menu) {
83 | getMenuInflater().inflate(R.menu.main_menu, menu);
84 |
85 |
86 | // Import menu items
87 | menuItemSettings = (MenuItem) menu.findItem(R.id.menu_action_settings);
88 | menuItemHelp = (MenuItem) menu.findItem(R.id.menu_action_help);
89 | registerMenuItemsClickListeners();
90 |
91 | // Retrieve the SearchView and plug it into SearchManager
92 | final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
93 | SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
94 | searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
95 |
96 | searchItem = menu.findItem(R.id.action_search);
97 |
98 | searchView.setQueryHint(getResources().getString(R.string.avi_search_hint));
99 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
100 | @Override
101 | public boolean onQueryTextChange(String newText) {
102 | // your text view here
103 | // textView.setText(newText);
104 | return false;
105 | }
106 |
107 | @Override
108 | public boolean onQueryTextSubmit(String query) {
109 | performSearch(query);
110 | return false;
111 | }
112 | });
113 |
114 | return true;
115 | }
116 |
117 | private void performSearch(String query) {
118 |
119 | if (Build.VERSION.SDK_INT > 14) {
120 | searchItem.collapseActionView();
121 | }
122 | startActivity(
123 | (new Intent(this, SearchActivity.class)).putExtra("query", query)
124 | );
125 | }
126 |
127 | /**
128 | * Load event handlers for menu buttons in paralel thread
129 | */
130 | private void registerMenuItemsClickListeners() {
131 | new Handler().postDelayed(new Runnable() {
132 | @Override
133 | public void run() {
134 | menuItemSettings.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
135 | @Override
136 | public boolean onMenuItemClick(MenuItem item) {
137 | Intent i = new Intent(getBaseContext(), SettingsActivity.class);
138 | startActivity(i);
139 | return false;
140 | }
141 | });
142 |
143 | menuItemHelp.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
144 | @Override
145 | public boolean onMenuItemClick(MenuItem item) {
146 | Intent i = new Intent(getBaseContext(), SupportActivity.class);
147 | startActivity(i);
148 | return false;
149 | }
150 | });
151 | }
152 | }, 100);
153 | }
154 |
155 | private void startUpdate(AviSemVersion newVer) {
156 | startActivity(
157 | new Intent(this, UpdateDownloaderActivity.class)
158 | .putExtra("update", newVer)
159 | );
160 | }
161 |
162 | private void showUpdateDialog(final AviSemVersion newVer) {
163 | OTAUpdateChecker.makeDialog(this, newVer)
164 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
165 | public void onClick(DialogInterface dialog, int id) {
166 | startUpdate(newVer);
167 | dialog.cancel();
168 | }
169 | }).show();
170 | }
171 |
172 | private void initBackgroundUpdateCheck() {
173 | final Context context = getApplicationContext();
174 | boolean allowNightlies = PreferenceManager.
175 | getDefaultSharedPreferences(context).
176 | getBoolean(getResources().getString(R.string.avi_prop_allow_unstable), false);
177 |
178 | OTAUpdateChecker.checkForUpdates(new OTAStateListener() {
179 | @Override
180 | protected void onUpdateAvailable(AviSemVersion availableVersion, AviSemVersion currentVersion) {
181 | showUpdateDialog(availableVersion);
182 | }
183 | }, allowNightlies);
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import android.content.Intent;
4 | import android.os.Handler;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.os.Bundle;
7 |
8 | import com.rollbar.android.Rollbar;
9 |
10 | public class MainActivity extends AppCompatActivity {
11 |
12 | protected int SPLASH_DISPLAY_LENGTH = 300;
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 |
18 | if (!BuildConfig.DEBUG) {
19 | // Init Rollbar monitor on release
20 | Rollbar.init(this, "b2769f6943314e52be560fe9c2ab7626", "production");
21 | }
22 | }
23 |
24 | @Override
25 | protected void onPostCreate(Bundle savedInstanceState) {
26 | super.onPostCreate(savedInstanceState);
27 |
28 | new Handler().postDelayed(new Runnable(){
29 | @Override
30 | public void run() {
31 | Intent mainIntent = new Intent(MainActivity.this, DashboardActivity.class);
32 | MainActivity.this.startActivity(mainIntent);
33 | overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
34 | MainActivity.this.finish();
35 | }
36 | }, SPLASH_DISPLAY_LENGTH);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/RecyclerTouchListener.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.GestureDetector;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 |
9 | public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
10 | private GestureDetector gestureDetector;
11 | private ClickListener clickListener;
12 |
13 | public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
14 | this.clickListener = clickListener;
15 | gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
16 | @Override
17 | public boolean onSingleTapUp(MotionEvent e) {
18 | return true;
19 | }
20 |
21 | @Override
22 | public void onLongPress(MotionEvent e) {
23 | View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
24 | if (child != null && clickListener != null) {
25 | clickListener.onLongClick(child, recyclerView.getChildPosition(child));
26 | }
27 | }
28 | });
29 | }
30 |
31 | @Override
32 | public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
33 |
34 | View child = rv.findChildViewUnder(e.getX(), e.getY());
35 | if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
36 | clickListener.onClick(child, rv.getChildPosition(child));
37 | }
38 | return false;
39 | }
40 |
41 | @Override
42 | public void onTouchEvent(RecyclerView rv, MotionEvent e) {
43 | }
44 |
45 | @Override
46 | public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/SearchWidgetProvider.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import android.app.PendingIntent;
4 | import android.appwidget.AppWidgetManager;
5 | import android.appwidget.AppWidgetProvider;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.widget.RemoteViews;
9 |
10 | public class SearchWidgetProvider extends AppWidgetProvider {
11 | @Override
12 | public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
13 | for (int i = 0; i < appWidgetIds.length; i++) {
14 | int appWidgetId = appWidgetIds[i];
15 |
16 | Intent intent = new Intent(context, SearchActivity.class);
17 | PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
18 |
19 | RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_search);
20 | views.setOnClickPendingIntent(R.id.search_widget_layout, pendingIntent);
21 | appWidgetManager.updateAppWidget(appWidgetId, views);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/SupportActivity.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.MenuItem;
6 | import android.webkit.WebView;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Arrays;
10 | import java.util.List;
11 | import java.util.Locale;
12 |
13 | public class SupportActivity extends AppCompatActivity {
14 |
15 | private String[] langs = new String[]{"ru", "uk"};
16 | private List langsList = new ArrayList();
17 | WebView webView;
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | langsList.addAll(Arrays.asList(langs));
22 |
23 | setContentView(R.layout.activity_support);
24 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
25 | }
26 |
27 | @Override
28 | protected void onPostCreate(Bundle savedInstanceState) {
29 | super.onPostCreate(savedInstanceState);
30 |
31 | webView = (WebView) findViewById(R.id.webview_support);
32 | Locale cLocale = getResources().getConfiguration().locale;
33 | String cLanguage = cLocale.getLanguage();
34 |
35 | String fileLangPrefix = (langsList.contains(cLanguage)) ? cLanguage : "en";
36 | webView.loadUrl("file:///android_asset/help-" + fileLangPrefix + ".html");
37 |
38 | cLocale = null;
39 | cLanguage = null;
40 | }
41 |
42 | @Override
43 | public boolean onOptionsItemSelected(MenuItem item) {
44 | switch (item.getItemId()) {
45 | case android.R.id.home:
46 | finish();
47 | return true;
48 | }
49 |
50 | return super.onOptionsItemSelected(item);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/adapter/CachedMoviesListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.adapter;
2 |
3 |
4 | import android.content.Context;
5 | import android.support.v7.widget.GridLayoutManager;
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.LinearLayout;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 | import java.util.Locale;
18 |
19 | import com.bumptech.glide.Glide;
20 | import com.kinopoisk.Constants;
21 | import com.x1unix.avi.R;
22 | import com.x1unix.avi.model.KPMovie;
23 | import com.x1unix.avi.model.KPMovieItem;
24 |
25 | public class CachedMoviesListAdapter extends RecyclerView.Adapter {
26 |
27 | private ArrayList movies;
28 | private int rowLayout;
29 | private Context context;
30 | private String currentLang = "ru";
31 | private MovieViewHolder movieViewHolder;
32 |
33 |
34 | public static class MovieViewHolder extends RecyclerView.ViewHolder {
35 | LinearLayout moviesLayout;
36 | TextView movieTitle;
37 | TextView data;
38 | TextView movieDescription;
39 | TextView rating;
40 | ImageView posterView;
41 | String kpId;
42 | Context context;
43 |
44 |
45 | public MovieViewHolder(View v) {
46 | super(v);
47 | moviesLayout = (LinearLayout) v.findViewById(R.id.movies_layout);
48 | movieTitle = (TextView) v.findViewById(R.id.title);
49 | data = (TextView) v.findViewById(R.id.subtitle);
50 | movieDescription = (TextView) v.findViewById(R.id.description);
51 | rating = (TextView) v.findViewById(R.id.rating);
52 | posterView = (ImageView) v.findViewById(R.id.poster_preview);
53 | context = v.getContext();
54 | }
55 |
56 | public void loadPoster(Context context) {
57 | Glide.with(context)
58 | .load(Constants.getPosterUrl(kpId))
59 | .placeholder(R.drawable.no_poster)
60 | .into(posterView);
61 | }
62 | }
63 |
64 | public CachedMoviesListAdapter(ArrayList movies, int rowLayout, Context context, Locale currentLocale) {
65 | this.movies = movies;
66 | this.rowLayout = rowLayout;
67 | this.context = context;
68 | this.currentLang = currentLocale.getLanguage();
69 | }
70 |
71 | @Override
72 | public CachedMoviesListAdapter.MovieViewHolder onCreateViewHolder(ViewGroup parent,
73 | int viewType) {
74 | View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
75 | return new MovieViewHolder(view);
76 | }
77 |
78 |
79 | @Override
80 | public void onBindViewHolder(MovieViewHolder holder, final int position) {
81 | KPMovie cMovie = movies.get(position);
82 | holder.movieTitle.setText(cMovie.getLocalizedTitle(currentLang));
83 | holder.data.setText(cMovie.getYear());
84 | holder.movieDescription.setText(cMovie.getShortDescription());
85 | holder.rating.setText(String.valueOf(cMovie.getStars()));
86 | holder.kpId = cMovie.getId();
87 | holder.loadPoster(context);
88 | }
89 |
90 | @Override
91 | public int getItemCount() {
92 | return (movies == null) ? 0 : movies.size();
93 | }
94 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/adapter/MoviesAdapter.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.GridLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.LinearLayout;
11 | import android.widget.TextView;
12 | import android.widget.Toast;
13 |
14 | import java.util.List;
15 | import java.util.Locale;
16 |
17 | import com.bumptech.glide.Glide;
18 | import com.kinopoisk.Constants;
19 | import com.x1unix.avi.R;
20 | import com.x1unix.avi.model.KPMovieItem;
21 |
22 | public class MoviesAdapter extends RecyclerView.Adapter {
23 |
24 | private List movies;
25 | private int rowLayout;
26 | private Context context;
27 | private String currentLang = "ru";
28 |
29 |
30 | public static class MovieViewHolder extends RecyclerView.ViewHolder {
31 | LinearLayout moviesLayout;
32 | TextView movieTitle;
33 | TextView data;
34 | TextView movieDescription;
35 | TextView rating;
36 | ImageView posterView;
37 | String kpId;
38 | Context context;
39 |
40 |
41 | public MovieViewHolder(View v) {
42 | super(v);
43 | moviesLayout = (LinearLayout) v.findViewById(R.id.movies_layout);
44 | movieTitle = (TextView) v.findViewById(R.id.title);
45 | data = (TextView) v.findViewById(R.id.subtitle);
46 | movieDescription = (TextView) v.findViewById(R.id.description);
47 | rating = (TextView) v.findViewById(R.id.rating);
48 | posterView = (ImageView) v.findViewById(R.id.poster_preview);
49 | context = v.getContext();
50 | }
51 |
52 | public void loadPoster(Context context) {
53 | Glide.with(context)
54 | .load(Constants.getPosterUrl(kpId))
55 | .placeholder(R.drawable.no_poster)
56 | .into(posterView);
57 | }
58 | }
59 |
60 | public MoviesAdapter(List movies, int rowLayout, Context context, Locale currentLocale) {
61 | this.movies = movies;
62 | this.rowLayout = rowLayout;
63 | this.context = context;
64 | this.currentLang = currentLocale.getLanguage();
65 |
66 | // Show toast message if no items
67 | if (getItemCount() == 0) {
68 | Toast noItemsMsg = Toast.makeText(
69 | context,
70 | context.getResources().getString(R.string.avi_no_items_msg),
71 | Toast.LENGTH_LONG);
72 | noItemsMsg.show();
73 | }
74 | }
75 |
76 | @Override
77 | public MoviesAdapter.MovieViewHolder onCreateViewHolder(ViewGroup parent,
78 | int viewType) {
79 | View view = LayoutInflater.from(parent.getContext()).inflate(rowLayout, parent, false);
80 | return new MovieViewHolder(view);
81 | }
82 |
83 |
84 | @Override
85 | public void onBindViewHolder(MovieViewHolder holder, final int position) {
86 | KPMovieItem cMovie = movies.get(position);
87 | holder.movieTitle.setText(cMovie.getLocalizedTitle(currentLang));
88 | holder.data.setText(cMovie.getReleaseDate());
89 | holder.movieDescription.setText(cMovie.getDescription());
90 | holder.rating.setText(String.valueOf(cMovie.getVoteAverage()));
91 | holder.kpId = cMovie.getId();
92 | holder.loadPoster(context);
93 | }
94 |
95 | @Override
96 | public int getItemCount() {
97 | return (movies == null) ? 0 : movies.size();
98 | }
99 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/dashboard/DashboardFragmentPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.dashboard;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.app.FragmentManager;
7 | import android.support.v4.app.FragmentPagerAdapter;
8 |
9 | import com.x1unix.avi.R;
10 | import com.x1unix.avi.storage.MoviesRepository;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | public class DashboardFragmentPagerAdapter extends FragmentPagerAdapter {
16 | private final int tabTitles[] = new int[] { R.string.favorites, R.string.viewed};
17 | private final List fragments = new ArrayList<>();
18 | private Context context;
19 | private Resources res;
20 |
21 | public DashboardFragmentPagerAdapter(FragmentManager fm, Context context, MoviesRepository aMoviesRepository) {
22 | super(fm);
23 | this.context = context;
24 | this.res = context.getResources();
25 |
26 | // Add two test fragments
27 | this.fragments.add(FavoritesTabFragment.getInstance(aMoviesRepository));
28 | this.fragments.add(HistoryTabFragment.getInstance(aMoviesRepository));
29 | }
30 |
31 | @Override
32 | public int getCount() {
33 | return fragments.size();
34 | }
35 |
36 | @Override
37 | public Fragment getItem(int position) {
38 | return fragments.get(position);
39 | }
40 |
41 | @Override
42 | public CharSequence getPageTitle(int position) {
43 | // Generate title based on item position
44 | return res.getString(tabTitles[position]);
45 | }
46 |
47 | public void triggerUpdate() {
48 | for (DashboardTabFragment tab: fragments) {
49 | tab.updateLayout();
50 | }
51 | }
52 |
53 | public void triggerRescan() {
54 | for (DashboardTabFragment tab: fragments) {
55 | tab.rescanElements();
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/dashboard/FavoritesTabFragment.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.dashboard;
2 |
3 | import com.x1unix.avi.R;
4 | import android.os.Bundle;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import com.x1unix.avi.model.KPMovie;
9 | import com.x1unix.avi.storage.MoviesRepository;
10 | import java.util.ArrayList;
11 |
12 | public class FavoritesTabFragment extends DashboardTabFragment {
13 |
14 | @Override
15 | protected ArrayList getContentItems() {
16 | return moviesRepository.getFavoritesMovies();
17 | }
18 |
19 | @Override
20 | protected int getTabView() {
21 | return R.layout.tab_favorites;
22 | }
23 |
24 | @Override
25 | public void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | }
28 |
29 | @Override
30 | protected String getPlaylistGenitivusName() {
31 | return getResources().getString(R.string.playlist_genitivus_favorites);
32 | }
33 |
34 | @Override
35 | protected boolean onItemRemoveRequest(KPMovie item) {
36 | moviesRepository.removeFromFavorites(item.getId());
37 | return true;
38 | }
39 |
40 | @Override
41 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
42 | Bundle savedInstanceState) {
43 | return super.onCreateView(inflater, container, savedInstanceState);
44 | }
45 |
46 | public static DashboardTabFragment getInstance(MoviesRepository m) {
47 | return (new FavoritesTabFragment()).setMoviesRepository(m);
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/dashboard/HistoryTabFragment.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.dashboard;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import com.x1unix.avi.R;
8 | import com.x1unix.avi.model.KPMovie;
9 | import com.x1unix.avi.storage.MoviesRepository;
10 |
11 | import java.util.ArrayList;
12 |
13 | public class HistoryTabFragment extends DashboardTabFragment {
14 |
15 | @Override
16 | protected ArrayList getContentItems() {
17 | return moviesRepository.getViewedMovies();
18 | }
19 |
20 | @Override
21 | protected int getTabView() {
22 | return R.layout.tab_history;
23 | }
24 |
25 | @Override
26 | public void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | }
29 |
30 | @Override
31 | protected boolean onItemRemoveRequest(KPMovie item) {
32 | moviesRepository.removeFromHistory(item.getId());
33 | return true;
34 | }
35 |
36 | @Override
37 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
38 | Bundle savedInstanceState) {
39 | return super.onCreateView(inflater, container, savedInstanceState);
40 | }
41 |
42 | public static DashboardTabFragment getInstance(MoviesRepository m) {
43 | return (new HistoryTabFragment()).setMoviesRepository(m);
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/helpers/AdBlocker.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.helpers;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.os.AsyncTask;
6 | import android.os.Build;
7 | import android.support.annotation.WorkerThread;
8 | import android.text.TextUtils;
9 | import android.util.Log;
10 | import android.webkit.WebResourceResponse;
11 |
12 | import java.io.ByteArrayInputStream;
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 | import java.net.URI;
16 | import java.net.URISyntaxException;
17 | import java.util.HashSet;
18 | import java.util.Set;
19 |
20 | import okhttp3.HttpUrl;
21 | import okio.BufferedSource;
22 | import okio.Okio;
23 |
24 | public class AdBlocker {
25 | private static final String AD_HOSTS_FILE = "hosts.txt";
26 | private static final String BAD_URLS_FILE = "urls.txt";
27 | private static final Set AD_HOSTS = new HashSet<>();
28 | private static final Set BAD_URS = new HashSet<>();
29 |
30 | public static void init(final Context context) {
31 | new AsyncTask() {
32 | @Override
33 | protected Void doInBackground(Void... params) {
34 | try {
35 | loadFromAssets(context);
36 | } catch (IOException e) {
37 | // noop
38 | }
39 | return null;
40 | }
41 | }.execute();
42 | }
43 |
44 | @WorkerThread
45 | private static void loadFromAssets(Context context) throws IOException {
46 | InputStream stream = context.getAssets().open(AD_HOSTS_FILE);
47 | BufferedSource buffer = Okio.buffer(Okio.source(stream));
48 | String line;
49 | while ((line = buffer.readUtf8Line()) != null) {
50 | AD_HOSTS.add(line);
51 | }
52 | buffer.close();
53 | stream.close();
54 |
55 | loadUrlsFromAssets(context);
56 | }
57 |
58 | private static void loadUrlsFromAssets(Context context) throws IOException {
59 | InputStream stream = context.getAssets().open(BAD_URLS_FILE);
60 | BufferedSource buffer = Okio.buffer(Okio.source(stream));
61 | String line;
62 | while ((line = buffer.readUtf8Line()) != null) {
63 | BAD_URS.add(line);
64 | }
65 | buffer.close();
66 | stream.close();
67 | }
68 |
69 | public static boolean isBadUrl(String url) {
70 | return BAD_URS.contains(url);
71 | }
72 |
73 | public static boolean isAd(String url) {
74 | String host;
75 | try {
76 | host = getDomainName(url);
77 | } catch(Exception ex) {
78 | return false;
79 | }
80 | return isBadUrl(url) || isAdHost(host);
81 | }
82 |
83 | public static String getDomainName(String url) throws URISyntaxException {
84 | URI uri = new URI(url);
85 | String domain = uri.getHost();
86 | return domain.startsWith("www.") ? domain.substring(4) : domain;
87 | }
88 |
89 | private static boolean isAdHost(String host) {
90 | if (TextUtils.isEmpty(host)) {
91 | return false;
92 | }
93 | int index = host.indexOf(".");
94 | return index >= 0 && (AD_HOSTS.contains(host) ||
95 | index + 1 < host.length() && isAdHost(host.substring(index + 1)));
96 | }
97 |
98 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
99 | public static WebResourceResponse createEmptyResource() {
100 | return new WebResourceResponse("text/plain", "UTF-8", new ByteArrayInputStream("".getBytes()));
101 | }
102 |
103 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
104 | public static WebResourceResponse createEmptyResource(String type) {
105 | return new WebResourceResponse(type, "UTF-8", new ByteArrayInputStream("".getBytes()));
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/helpers/DownloadFileFromURL.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.helpers;
2 |
3 | import android.os.AsyncTask;
4 | import android.os.Environment;
5 | import android.util.Log;
6 |
7 | import java.io.BufferedInputStream;
8 | import java.io.FileOutputStream;
9 | import java.io.InputStream;
10 | import java.io.OutputStream;
11 | import java.net.URL;
12 | import java.net.URLConnection;
13 |
14 | public class DownloadFileFromURL extends AsyncTask {
15 | private String LOG_TAG = "OTA_Downloader";
16 | public boolean failed = false;
17 | public String error = "";
18 |
19 | @Override
20 | protected void onPreExecute() {
21 | super.onPreExecute();
22 | }
23 |
24 | @Override
25 | protected String doInBackground(String... f_url) {
26 | int count;
27 | try {
28 | URL url = new URL(f_url[0]);
29 | String fileName = f_url[1];
30 | URLConnection conection = url.openConnection();
31 | conection.connect();
32 | // this will be useful so that you can show a tipical 0-100% progress bar
33 | int lenghtOfFile = conection.getContentLength();
34 |
35 | // download the file
36 | InputStream input = new BufferedInputStream(url.openStream(), 8192);
37 |
38 | // Output stream
39 | OutputStream output = new FileOutputStream(Environment
40 | .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + fileName);
41 |
42 | byte data[] = new byte[1024];
43 |
44 | long total = 0;
45 |
46 | while ((count = input.read(data)) != -1) {
47 | total += count;
48 | // publishing the progress....
49 | // After this onProgressUpdate will be called
50 | publishProgress(""+(int)((total*100)/lenghtOfFile));
51 |
52 | // writing data to file
53 | output.write(data, 0, count);
54 | }
55 |
56 | // flushing output
57 | output.flush();
58 |
59 | // closing streams
60 | output.close();
61 | input.close();
62 |
63 | } catch (Exception e) {
64 | Log.e(LOG_TAG, e.getMessage());
65 | failed = true;
66 | error = e.getMessage();
67 | }
68 |
69 | return null;
70 | }
71 |
72 | protected void onError(String error) {}
73 |
74 | protected void onProgressUpdate(String... progress) {}
75 |
76 | @Override
77 | protected void onPostExecute(String file_url) {}
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/helpers/PermissionHelper.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.helpers;
2 |
3 | import android.Manifest;
4 | import android.annotation.SuppressLint;
5 | import android.annotation.TargetApi;
6 | import android.app.Activity;
7 | import android.content.pm.PackageManager;
8 | import android.support.v4.app.ActivityCompat;
9 | import android.support.v4.content.ContextCompat;
10 |
11 | import java.lang.annotation.Target;
12 |
13 | /**
14 | * This file contains permission helpers for Android 7+
15 | */
16 |
17 | public class PermissionHelper {
18 | // Storage Permissions
19 | public static final int REQUEST_EXTERNAL_STORAGE = 1;
20 |
21 | @SuppressLint("NewApi")
22 | private static String[] PERMISSIONS_STORAGE = {
23 | Manifest.permission.READ_EXTERNAL_STORAGE,
24 | Manifest.permission.WRITE_EXTERNAL_STORAGE
25 | };
26 |
27 | /**
28 | * Checks if the app has permission to write to device storage
29 | *
30 | * If the app does not has permission then the user will be prompted to grant permissions
31 | *
32 | * @param activity
33 | */
34 | public static void verifyStoragePermissions(Activity activity) {
35 | // Check if we have write permission
36 | int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
37 |
38 | if (permission != PackageManager.PERMISSION_GRANTED) {
39 | // We don't have permission so prompt the user
40 | ActivityCompat.requestPermissions(
41 | activity,
42 | PERMISSIONS_STORAGE,
43 | REQUEST_EXTERNAL_STORAGE
44 | );
45 | }
46 | }
47 |
48 | public static boolean hasPermissions(Activity activity, String permission) {
49 | return (ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED);
50 | }
51 |
52 | public static boolean hasWritePermission(Activity activity) {
53 | return hasPermissions(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
54 | }
55 |
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/model/AviSemVersion.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.model;
2 |
3 | import android.util.Log;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 | import com.x1unix.avi.BuildConfig;
7 | import com.x1unix.avi.updateManager.ISO8601;
8 |
9 | import java.io.Serializable;
10 | import java.text.ParseException;
11 | import java.util.Calendar;
12 | import java.util.regex.Pattern;
13 |
14 | public class AviSemVersion implements Serializable{
15 | @SerializedName("version")
16 | protected String original = "0.0.0";
17 |
18 | @SerializedName("stable")
19 | protected boolean stable = true;
20 |
21 | @SerializedName("tag")
22 | protected String tag;
23 |
24 | @SerializedName("date")
25 | protected String date;
26 |
27 | @SerializedName("downs")
28 | protected int downloadsCount = 0;
29 |
30 | @SerializedName("apk")
31 | protected String apkUrl;
32 |
33 | @SerializedName("homepage")
34 | protected String homepage;
35 |
36 | @SerializedName("changelog")
37 | protected String changelog;
38 |
39 | public AviSemVersion(String semVerString, boolean isStable, String tag, String date,
40 | int downs, String apkUrl, String homepage) {
41 | this.original = semVerString;
42 | this.stable = isStable;
43 | this.tag = tag;
44 | this.date = date;
45 | this.downloadsCount = downs;
46 | this.apkUrl = apkUrl;
47 | this.homepage = homepage;
48 | }
49 |
50 | public AviSemVersion(String semVerString) {
51 | this.original = semVerString;
52 | }
53 |
54 | public String getApkUrl() {
55 | return this.apkUrl;
56 | }
57 |
58 | public String getHomePageUrl() {
59 | return this.homepage;
60 | }
61 |
62 | public String toString() {
63 | return this.original;
64 | }
65 |
66 | public Calendar getReleaseDate() throws ParseException {
67 | return ISO8601.toCalendar(this.date);
68 | }
69 |
70 | public boolean hasChangelog() {
71 | return this.changelog != null;
72 | }
73 | public String getChangelog() {
74 | return this.changelog;
75 | }
76 |
77 | public String getTag() {
78 | return this.tag;
79 | }
80 |
81 | public static AviSemVersion getApplicationVersion() {
82 | return new AviSemVersion(BuildConfig.VERSION_NAME);
83 | }
84 |
85 | public boolean isStable() {
86 | return stable;
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/model/KPMovie.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class KPMovie {
9 | @SerializedName("filmID")
10 | private String filmID;
11 |
12 | @SerializedName("nameRU")
13 | private String nameRU;
14 |
15 | @SerializedName("nameEN")
16 | private String nameEN;
17 |
18 | @SerializedName("year")
19 | private String year;
20 |
21 | @SerializedName("filmLength")
22 | private String filmLength;
23 |
24 | @SerializedName("county")
25 | private String country;
26 |
27 | @SerializedName("genre")
28 | private String genre;
29 |
30 | @SerializedName("description")
31 | private String description;
32 |
33 | @SerializedName("ratingMPAA")
34 | private String ratingMPAA;
35 |
36 | @SerializedName("ratingAgeLimits")
37 | private String ratingAgeLimits;
38 |
39 | @SerializedName("type")
40 | private String type;
41 |
42 | @SerializedName("creators")
43 | private List creators;
44 |
45 | // Values stored in db
46 | private String shortDescription = "";
47 |
48 | private String stars = "5.0";
49 |
50 | public KPMovie(String ifilmID, String inameRU, String inameEN, String iyear, String ifilmLength,
51 | String icountry, String igenre, String idescription, String iratingMPAA,
52 | String iratingAgeLimits, String itype, List icreators,
53 | String ishortDescription, String istars) {
54 | filmID = ifilmID;
55 | nameRU = inameRU;
56 | nameEN = inameEN;
57 | year = iyear;
58 | filmLength = ifilmLength;
59 | country = icountry;
60 | genre = igenre;
61 | description = idescription;
62 | ratingMPAA = iratingMPAA;
63 | ratingAgeLimits = iratingAgeLimits;
64 | type = itype;
65 | creators = icreators;
66 | shortDescription = ishortDescription;
67 | stars = istars;
68 | }
69 |
70 | public String getId() {
71 | return filmID;
72 | }
73 |
74 | public String getYear() {
75 | return year;
76 | }
77 |
78 | public String getFilmLength() {
79 | return filmLength;
80 | }
81 |
82 | public String getCountry() {
83 | return country;
84 | }
85 |
86 | public String getDescription() {
87 | return (description == null) ? "" : description;
88 | }
89 |
90 | public String getGenre() {
91 | return genre;
92 | }
93 |
94 | public String getRatingMPAA() {
95 | String value;
96 | if (ratingMPAA != null) {
97 | value = ratingMPAA + " (" + ratingAgeLimits + "+)";
98 | } else if (ratingAgeLimits != null) {
99 | value = ratingAgeLimits;
100 | } else {
101 | value = "-";
102 | }
103 | return value;
104 | }
105 |
106 | public String getTrueRatingMPAA() {
107 | return ratingMPAA;
108 | }
109 |
110 | public String getRatingAgeLimits() {
111 | return ratingAgeLimits;
112 | }
113 |
114 | public String getType() {
115 | return type;
116 | }
117 |
118 | public KPPeople[] getDirectors() {
119 | KPPeople[] result;
120 | boolean found = false;
121 | if ((creators == null) || (creators.size() == 0)) {
122 | result = new KPPeople[]{};
123 | } else {
124 | found = true;
125 | result = creators.get(0);
126 | }
127 | return result;
128 | }
129 |
130 | public KPPeople[] getActors() {
131 | KPPeople[] result;
132 | if ((creators == null) || (creators.size() < 2)) {
133 | result = new KPPeople[]{};
134 | } else {
135 | result = creators.get(1);
136 | }
137 | return result;
138 | }
139 |
140 | public KPPeople[] getProducers() {
141 | KPPeople[] result;
142 | if ((creators == null) || (creators.size() < 3)) {
143 | result = new KPPeople[]{};
144 | } else {
145 | result = creators.get(2);
146 | }
147 | return result;
148 | }
149 |
150 | public String getNameRU() {
151 | return this.nameRU;
152 | }
153 |
154 | public String getNameEN() {
155 | return this.nameEN;
156 | }
157 |
158 | public List getCreators() {
159 | return creators;
160 | }
161 |
162 | public KPMovie setStars(String istars) {
163 | stars = istars;
164 | return this;
165 | }
166 |
167 | public KPMovie setShortDescription(String idescription) {
168 | shortDescription = idescription;
169 | return this;
170 | }
171 |
172 | public String getLocalizedTitle(String currentLocale) {
173 | Boolean isSlavic = ( currentLocale.equals("ru") || currentLocale.equals("uk") );
174 | Boolean isSlavicAvailable = (nameRU != null) && (nameRU.length() > 0);
175 | Boolean isLatinAvailable = (nameEN != null) && (nameEN.length() > 0);
176 |
177 | String title = nameRU;
178 |
179 | if (isSlavic) {
180 | if (isSlavicAvailable) {
181 | title = nameRU;
182 | } else {
183 | title = nameEN;
184 | }
185 | } else {
186 | if (isLatinAvailable) {
187 | title = nameEN;
188 | } else {
189 | title = nameRU;
190 | }
191 | }
192 |
193 | return title;
194 | }
195 |
196 | public String getStars() {
197 | return (stars == null) ? "5.0" : stars;
198 | }
199 |
200 | public String getShortDescription() {
201 | return shortDescription;
202 | }
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/model/KPMovieDetailViewResponse.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | /**
6 | * Created by ascii on 27.11.2016.
7 | */
8 |
9 | public class KPMovieDetailViewResponse {
10 | @SerializedName("resultCode")
11 | protected int resultCode = 0;
12 |
13 | @SerializedName("message")
14 | protected String message = "";
15 |
16 | @SerializedName("data")
17 | protected KPMovie data;
18 |
19 | public KPMovieDetailViewResponse(int code, String msg, KPMovie res) {
20 | resultCode = code;
21 | message = msg;
22 | data = res;
23 | };
24 |
25 | public KPMovie getResult() {
26 | return data;
27 | }
28 |
29 | public String getMessage() {
30 | return (message == null) ? "" : message;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/model/KPMovieItem.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.model;
2 |
3 | import android.util.Log;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class KPMovieItem {
11 | @SerializedName("id")
12 | public String id;
13 |
14 | @SerializedName("nameRU")
15 | public String nameRu;
16 |
17 | @SerializedName("nameEN")
18 | public String nameEn;
19 |
20 | @SerializedName("description")
21 | public String description;
22 |
23 | @SerializedName("posterURL")
24 | public String posterUrl;
25 |
26 | @SerializedName("year")
27 | public String year;
28 |
29 | @SerializedName("filmLength")
30 | public String duration;
31 |
32 | @SerializedName("county")
33 | public String country;
34 |
35 | @SerializedName("genre")
36 | public String genre;
37 |
38 | @SerializedName("rating")
39 | public String rating;
40 |
41 | public KPMovieItem(String id, String nameRu, String nameEn, String description, String posterUrl,
42 | String year, String duration, String country, String genre, String rating) {
43 | this.id = id;
44 | this.nameRu = nameRu;
45 | this.nameEn = nameEn;
46 | this.description = description;
47 | this.posterUrl = posterUrl;
48 | this.year = year;
49 | this.duration = duration;
50 | this.country = country;
51 | this.genre = genre;
52 | this.rating = rating;
53 | }
54 |
55 | public String getTitle() {
56 | if((this.nameRu == null) || (this.nameRu.length() == 0)) {
57 | return this.nameEn;
58 | } else {
59 | return this.nameRu;
60 | }
61 | }
62 |
63 | public String getLocalizedTitle(String currentLocale) {
64 | Boolean isSlavic = ( currentLocale.equals("ru") || currentLocale.equals("uk") );
65 | Boolean isSlavicAvailable = (nameRu != null) && (nameRu.length() > 0);
66 | Boolean isLatinAvailable = (nameEn != null) && (nameEn.length() > 0);
67 |
68 | if (isSlavic) {
69 | if (isSlavicAvailable) {
70 | return nameRu;
71 | } else {
72 | return nameEn;
73 | }
74 | } else {
75 | if (isLatinAvailable) {
76 | return nameEn;
77 | } else {
78 | return nameRu;
79 | }
80 | }
81 | }
82 |
83 | public String getReleaseDate() {
84 | return this.year;
85 | }
86 |
87 | public String getDescription() {
88 | return this.description;
89 | }
90 |
91 | public String getGenre() {
92 | return (this.genre == null) ? "" : this.genre;
93 | }
94 | public String getRating() {
95 | return (this.rating == null) ? "" : this.rating;
96 | }
97 |
98 | public double getVoteAverage() {
99 | if (this.rating == null) return 0;
100 | String splited[] = this.rating.split(" ");
101 | double val = 0;
102 | try {
103 | val = (splited.length > 0) ? Double.parseDouble(splited[0]) : 0;
104 | } catch(Exception ex) {
105 | val = 0;
106 | }
107 | return val;
108 | }
109 |
110 | public String getId() {
111 | return this.id;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/model/KPMovieSearchResult.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class KPMovieSearchResult {
9 | @SerializedName("keyword")
10 | private String keyword;
11 |
12 | @SerializedName("pagesCount")
13 | private String pagesTotal;
14 |
15 | @SerializedName("searchFilms")
16 | private List results = new ArrayList();
17 |
18 | public KPMovieSearchResult(String keyword, String pagesTotal, String itemsTotal, List results) {
19 | this.keyword = keyword;
20 | this.pagesTotal = pagesTotal;
21 | this.results = results;
22 | }
23 |
24 | public int getTotalPages() {
25 | return Integer.parseInt(this.pagesTotal);
26 | }
27 |
28 | public void setTotalPages(String total) {
29 | this.pagesTotal = total;
30 | }
31 |
32 | public void setKeyword(String keyword) {
33 | this.keyword = keyword;
34 | }
35 |
36 | public void setResults(List items) {
37 | this.results = items;
38 | }
39 |
40 | public List getResults() {
41 | return this.results;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/model/KPPeople.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | public class KPPeople {
6 | @SerializedName("id")
7 | private String id;
8 |
9 | @SerializedName("type")
10 | private String type;
11 |
12 | @SerializedName("nameRU")
13 | private String nameRU;
14 |
15 | @SerializedName("nameEN")
16 | private String nameEN;
17 |
18 | @SerializedName("professionKey")
19 | private String professionKey;
20 |
21 |
22 |
23 | public KPPeople(String iid, String itype, String inameRU, String inameEN, String iprofessionKey) {
24 | id = iid;
25 | type = itype;
26 | nameRU = inameRU;
27 | nameEN = inameEN;
28 | professionKey = iprofessionKey;
29 | }
30 |
31 | public String getName(String currentLocale) {
32 | String value;
33 |
34 | try {
35 | Boolean isSlavic = ( currentLocale.equals("ru") || currentLocale.equals("uk") );
36 | Boolean isSlavicAvailable = (nameRU != null) && (nameRU.length() > 0);
37 | Boolean isLatinAvailable = (nameEN != null) && (nameEN.length() > 0);
38 |
39 |
40 | if (isSlavic) {
41 | if (isSlavicAvailable) {
42 | value = nameRU;
43 | } else {
44 | value = nameEN;
45 | }
46 | } else {
47 | if (isLatinAvailable) {
48 | value = nameEN;
49 | } else {
50 | value = nameRU;
51 | }
52 | }
53 | } catch (Exception ex) {
54 | value = null;
55 | }
56 |
57 | return value;
58 | }
59 |
60 | public String getId() {
61 | return id;
62 | }
63 |
64 | public String getType() {
65 | return type;
66 | }
67 |
68 | public String getRole() {
69 | return (professionKey == null) ? "unknown" : professionKey;
70 | }
71 |
72 | public boolean isActor() {
73 | return getRole().equals("actor");
74 | }
75 |
76 | public boolean isDirector() {
77 | return getRole().equals("director");
78 | }
79 |
80 | public boolean isProducer() {
81 | return getRole().equals("producer");
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/model/KPResponse.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | /**
6 | * Created by ascii on 27.11.2016.
7 | */
8 |
9 | public class KPResponse {
10 | @SerializedName("resultCode")
11 | protected int resultCode = 0;
12 |
13 | @SerializedName("message")
14 | protected String message = "";
15 |
16 |
17 | protected Object data;
18 |
19 | public KPResponse(int code, String message) {
20 | this.message = message;
21 | this.resultCode = code;
22 | }
23 |
24 | public Object getResult() {
25 | return data;
26 | }
27 |
28 | public String getMessage() {
29 | return (message == null) ? "" : message;
30 | }
31 |
32 | public int getResultCode() {
33 | return resultCode;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/model/KPSearchResponse.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.model;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | /**
6 | * Created by ascii on 25.11.2016.
7 | */
8 |
9 | public class KPSearchResponse {
10 | @SerializedName("resultCode")
11 | protected int resultCode = 0;
12 |
13 | @SerializedName("message")
14 | protected String message = "";
15 |
16 | @SerializedName("data")
17 | protected KPMovieSearchResult data;
18 |
19 | public KPSearchResponse(int code, String msg, KPMovieSearchResult res) {
20 | resultCode = code;
21 | message = msg;
22 | data = res;
23 | }
24 |
25 | public KPSearchResponse() {}
26 |
27 | public KPMovieSearchResult getData() {
28 | return data;
29 | }
30 |
31 | public String getMessage() {
32 | return message;
33 | }
34 |
35 | public int getResultCode() {
36 | return resultCode;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/rest/KPApiInterface.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.rest;
2 |
3 | import com.x1unix.avi.model.KPMovieDetailViewResponse;
4 | import com.x1unix.avi.model.KPSearchResponse;
5 |
6 | import retrofit2.Call;
7 | import retrofit2.http.GET;
8 | import retrofit2.http.Path;
9 | import retrofit2.http.Query;
10 |
11 |
12 | public interface KPApiInterface {
13 | @GET("getKPSearchInFilms")
14 | Call findMovies(@Query("keyword") String keyword);
15 |
16 | @GET("getKPFilmDetailView")
17 | Call getMovieById(@Query("filmID") String filmId);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/rest/KPRestClient.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.rest;
2 |
3 | import retrofit2.Retrofit;
4 |
5 | import com.kinopoisk.*;
6 |
7 | public class KPRestClient {
8 | public static final String BASE_URL = "https://ext.kinopoisk.ru/ios/3.11.0/";
9 | private static Retrofit retrofit = null;
10 |
11 | public static Retrofit getClient() {
12 | if (retrofit == null) {
13 | retrofit = (new NetworkApiFactory()).getClient();
14 | }
15 | return retrofit;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/storage/DBHelper.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.storage;
2 |
3 |
4 | import android.content.Context;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.database.sqlite.SQLiteOpenHelper;
7 |
8 | class DBHelper extends SQLiteOpenHelper {
9 |
10 | public DBHelper(Context context) {
11 | super(context, "avi", null, 1);
12 | }
13 |
14 | @Override
15 | public void onCreate(SQLiteDatabase db) {
16 | // Init db
17 | createMovies(db);
18 | createFavorites(db);
19 | createViewed(db);
20 | }
21 |
22 | private void createMovies(SQLiteDatabase db) {
23 | db.execSQL("CREATE TABLE movies (\n" +
24 | " filmID INT PRIMARY KEY\n" +
25 | " UNIQUE\n" +
26 | " NOT NULL,\n" +
27 | " nameRU VARCHAR (128) DEFAULT \"\",\n" +
28 | " nameEN VARCHAR (128) DEFAULT \"\",\n" +
29 | " year VARCHAR (12) DEFAULT \"\",\n" +
30 | " filmLength VARCHAR (10) DEFAULT 0,\n" +
31 | " country VARCHAR (48) DEFAULT \"\",\n" +
32 | " genre VARCHAR (64) DEFAULT \"\",\n" +
33 | " description TEXT DEFAULT \"\",\n" +
34 | " ratingMPAA VARCHAR (10) DEFAULT \"\",\n" +
35 | " ratingAgeLimits VARCHAR (5) DEFAULT \"\",\n" +
36 | " type VARCHAR (32) DEFAULT \"\",\n" +
37 | " creators BLOB DEFAULT \"\",\n" +
38 | " shortDescription VARCHAR (64) DEFAULT \"\",\n" +
39 | " stars VARCHAR (10) DEFAULT \"5.0\"" +
40 | ");");
41 | }
42 |
43 | private void createFavorites(SQLiteDatabase db) {
44 | db.execSQL("CREATE TABLE favorites (\n" +
45 | " filmID INT PRIMARY KEY\n" +
46 | " REFERENCES movies (filmID) \n" +
47 | " NOT NULL\n" +
48 | " UNIQUE\n" +
49 | ");\n");
50 | }
51 |
52 | private DBHelper createViewed(SQLiteDatabase db) {
53 | db.execSQL("CREATE TABLE viewed (\n" +
54 | " filmID INT PRIMARY KEY\n" +
55 | " REFERENCES movies (filmID) \n" +
56 | " NOT NULL\n" +
57 | " UNIQUE,\n" +
58 | " lastViewed BIGINT DEFAULT (0)" +
59 | ");\n");
60 |
61 | return this;
62 | }
63 |
64 | @Override
65 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
66 |
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/storage/MoviesRepository.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.storage;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteDatabase;
7 | import android.util.Log;
8 |
9 | import com.google.gson.Gson;
10 | import com.google.gson.reflect.TypeToken;
11 | import com.x1unix.avi.model.KPMovie;
12 | import com.x1unix.avi.model.KPPeople;
13 |
14 | import java.lang.reflect.Type;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | public class MoviesRepository {
19 |
20 | public static final String TABLE_MOVIES = "movies";
21 | public static final String TABLE_FAVORITES = "favorites";
22 | public static final String TABLE_VIEWED = "viewed";
23 |
24 | private static final String LOG_TAG = "MoviesRepository";
25 | public static final Type MOVIE_TYPE = new TypeToken>() {
26 | }.getType();
27 |
28 | private Context context;
29 | private DBHelper dbHelper;
30 | private SQLiteDatabase db;
31 | private Boolean connected = false;
32 |
33 | public MoviesRepository(Context context) {
34 | this.context = context;
35 | dbHelper = new DBHelper(context);
36 | connect();
37 | }
38 |
39 | public MoviesRepository addMovie(KPMovie movie) {
40 | ContentValues cv = new ContentValues();
41 |
42 | // Write basic fields
43 | cv.put("filmID", movie.getId());
44 | cv.put("nameRU", movie.getNameRU());
45 | cv.put("nameEN", movie.getNameEN());
46 | cv.put("year", movie.getYear());
47 | cv.put("filmLength", movie.getFilmLength());
48 | cv.put("country", movie.getCountry());
49 | cv.put("genre", movie.getGenre());
50 | cv.put("description", movie.getDescription());
51 | cv.put("ratingMPAA", movie.getTrueRatingMPAA());
52 | cv.put("ratingAgeLimits", movie.getRatingAgeLimits());
53 | cv.put("type", movie.getType());
54 | cv.put("shortDescription", movie.getShortDescription());
55 | cv.put("stars", movie.getStars());
56 |
57 | // Serialize data to JSON and save as BLOB
58 | cv.put("creators", (new Gson()).toJson(movie.getCreators()));
59 |
60 | // Write movie to db
61 | long rowID = db.insert(MoviesRepository.TABLE_MOVIES, null, cv);
62 | Log.d(MoviesRepository.LOG_TAG, "Movie row inserted, ID: " + rowID);
63 |
64 | return this;
65 | }
66 |
67 | public boolean movieExists(String kpId) {
68 | String query = "SELECT * FROM " + MoviesRepository.TABLE_MOVIES + " where filmID = " + kpId + ";";
69 | Cursor cursor = db.rawQuery(query, null);
70 |
71 | boolean exists = (cursor.getCount() > 0);
72 | cursor.close();
73 |
74 | return exists;
75 | }
76 |
77 | public boolean movieHistoryExists(String kpId) {
78 | String query = "SELECT * FROM " + MoviesRepository.TABLE_VIEWED + " where filmID = " + kpId + ";";
79 | Cursor cursor = db.rawQuery(query, null);
80 |
81 | boolean exists = (cursor.getCount() > 0);
82 | cursor.close();
83 |
84 | return exists;
85 | }
86 |
87 | public void addItemToHistory(String kpId) {
88 | ContentValues cv = new ContentValues();
89 | cv.put("filmID", kpId);
90 | cv.put("lastViewed", getCurrentTimeStamp());
91 |
92 | long rowID = db.insert(MoviesRepository.TABLE_VIEWED, null, cv);
93 | Log.d(MoviesRepository.LOG_TAG, "Movie added to history #" + kpId);
94 | }
95 |
96 | public void updateItemHistory(String kpId) {
97 | ContentValues cv = new ContentValues();
98 | cv.put("filmID", kpId);
99 | cv.put("lastViewed", getCurrentTimeStamp());
100 |
101 | db.update(MoviesRepository.TABLE_VIEWED, cv, "filmID="+kpId, null);
102 | }
103 |
104 | private long getCurrentTimeStamp() {
105 | return System.currentTimeMillis()/1000;
106 | }
107 |
108 | private String getSelect() {
109 | return "SELECT * FROM " + MoviesRepository.TABLE_MOVIES;
110 | }
111 |
112 | public KPMovie getMovieById(String filmId) {
113 | KPMovie movie = null;
114 | String query = getSelect() + " where filmID = " + filmId + ";";
115 | Cursor c = db.rawQuery(query, null);
116 |
117 | try {
118 | if ((c != null) && c.moveToFirst()) {
119 | movie = MoviesRepository.getMovieFromCursor(c);
120 | }
121 | } catch (Exception e) {
122 | Log.e(LOG_TAG, "Failed to get movie from cursor, query: \n" + query + "\n Message: " + e.getMessage());
123 | movie = null;
124 | }
125 |
126 | if (c != null) c.close();
127 |
128 | return movie;
129 | }
130 |
131 | public boolean isInFavorites(String kpId) {
132 | String query = "SELECT * FROM " + MoviesRepository.TABLE_FAVORITES + " where filmID = " + kpId + ";";
133 | Cursor cursor = db.rawQuery(query, null);
134 |
135 | boolean exists = (cursor.getCount() > 0);
136 | cursor.close();
137 |
138 | return exists;
139 | }
140 |
141 | public boolean removeFromFavorites(String kpId) {
142 | return db.delete(MoviesRepository.TABLE_FAVORITES, "filmID = " + kpId, null) > 0;
143 | }
144 |
145 | public boolean removeFromHistory(String kpId) {
146 | return db.delete(MoviesRepository.TABLE_VIEWED, "filmID = " + kpId, null) > 0;
147 | }
148 |
149 | public void addToFavorites(String kpId) {
150 | ContentValues cv = new ContentValues();
151 | cv.put("filmID", kpId);
152 |
153 | long rowID = db.insert(MoviesRepository.TABLE_FAVORITES, null, cv);
154 | Log.d(MoviesRepository.LOG_TAG, "Add to favorites, ID: " + rowID);
155 | }
156 |
157 | private ArrayList getMoviesFromPlaylist(String playlistName, String extraQuery) {
158 | ArrayList result = new ArrayList();
159 |
160 | if (extraQuery == null) extraQuery = "";
161 |
162 | String q = "select m.*\n" +
163 | " from movies m\n" +
164 | " join " + playlistName + " f\n" +
165 | " on m.filmID = f.filmID " + extraQuery + ";";
166 |
167 | Cursor c = db.rawQuery(q, null);
168 |
169 | if (c.moveToFirst()) {
170 | do {
171 | result.add(MoviesRepository.getMovieFromCursor(c));
172 | } while(c.moveToNext());
173 | }
174 |
175 | if (c != null && !c.isClosed()){
176 | c.close();
177 | }
178 |
179 | return result;
180 | }
181 |
182 | public ArrayList getFavoritesMovies() {
183 | return getMoviesFromPlaylist(TABLE_FAVORITES, null);
184 | }
185 |
186 | public ArrayList getViewedMovies() {
187 | return getMoviesFromPlaylist(TABLE_VIEWED, "order by f.lastViewed DESC limit 80");
188 | }
189 |
190 | public void close() {
191 | connected = false;
192 | db.close();
193 | }
194 |
195 | public void connect() {
196 | db = dbHelper.getWritableDatabase();
197 | connected = true;
198 | }
199 |
200 | private static String getStringValue(String value, Cursor c) {
201 | return c.getString(c.getColumnIndex(value));
202 | }
203 |
204 | public static KPMovie getMovieFromCursor(Cursor c) {
205 | String cr = getStringValue("creators", c);
206 |
207 | List p = (new Gson()).fromJson(cr, MOVIE_TYPE);
208 |
209 | return new KPMovie(
210 | getStringValue("filmID", c),
211 | getStringValue("nameRU", c),
212 | getStringValue("nameEN", c),
213 | getStringValue("year", c),
214 | getStringValue("filmLength", c),
215 | getStringValue("country", c),
216 | getStringValue("genre", c),
217 | getStringValue("description", c),
218 | getStringValue("ratingMPAA", c),
219 | getStringValue("ratingAgeLimits", c),
220 | getStringValue("type", c),
221 | p,
222 | getStringValue("shortDescription", c),
223 | getStringValue("stars", c)
224 | );
225 | }
226 |
227 | public static MoviesRepository getInstance(Context context) {
228 | return new MoviesRepository(context);
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/updateManager/BuildParser.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.updateManager;
2 |
3 | import org.apache.commons.lang3.time.DateUtils;
4 | import com.x1unix.avi.BuildConfig;
5 | import java.util.Calendar;
6 | import java.util.Date;
7 |
8 | public class BuildParser {
9 | public static boolean compareBuild(Calendar newCal) {
10 | int build = BuildConfig.VERSION_CODE;
11 | boolean isNew = false;
12 |
13 | try {
14 | Calendar cal = BuildParser.getBuildDate();
15 |
16 | long time = cal.getTime().getTime();
17 | long timeNew = newCal.getTime().getTime();
18 |
19 | isNew = (timeNew > time);
20 | } catch(Exception ex) {
21 | isNew = true;
22 | }
23 |
24 | return isNew;
25 |
26 | }
27 |
28 | public static Calendar getBuildDate() {
29 | int build = BuildConfig.VERSION_CODE;
30 | String buildString = String.valueOf(build);
31 | int year = Integer.valueOf(buildString.substring(0, 4));
32 | int month = Integer.valueOf(buildString.substring(4, 6));
33 | int day = Integer.valueOf(buildString.substring(6, 8));
34 |
35 | if (month > 0) month--;
36 |
37 | buildString = null;
38 |
39 | Calendar cal = Calendar.getInstance();
40 | cal.set(Calendar.YEAR, year);
41 | cal.set(Calendar.MONTH, month);
42 | cal.set(Calendar.DAY_OF_MONTH, day);
43 |
44 | return cal;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/updateManager/ISO8601.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.updateManager;
2 |
3 | import java.text.ParseException;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Calendar;
6 | import java.util.Date;
7 | import java.util.GregorianCalendar;
8 |
9 | /**
10 | * Helper class for handling a most common subset of ISO 8601 strings
11 | * (in the following format: "2008-03-01T13:00:00+01:00"). It supports
12 | * parsing the "Z" timezone, but many other less-used features are
13 | * missing.
14 | */
15 | public final class ISO8601 {
16 | /** Transform Calendar to ISO 8601 string. */
17 | public static String fromCalendar(final Calendar calendar) {
18 | Date date = calendar.getTime();
19 | String formatted = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
20 | .format(date);
21 | return formatted.substring(0, 22) + ":" + formatted.substring(22);
22 | }
23 |
24 | /** Get current date and time formatted as ISO 8601 string. */
25 | public static String now() {
26 | return fromCalendar(GregorianCalendar.getInstance());
27 | }
28 |
29 | /** Transform ISO 8601 string to Calendar. */
30 | public static Calendar toCalendar(final String iso8601string)
31 | throws ParseException {
32 | Calendar calendar = GregorianCalendar.getInstance();
33 | String s = iso8601string.replace("Z", "+00:00");
34 | try {
35 | s = s.substring(0, 22) + s.substring(23); // to get rid of the ":"
36 | } catch (IndexOutOfBoundsException e) {
37 | throw new ParseException("Invalid length", 0);
38 | }
39 | Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s);
40 | calendar.setTime(date);
41 | return calendar;
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/updateManager/OTARepoClientInterface.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.updateManager;
2 |
3 | import com.x1unix.avi.model.AviSemVersion;
4 |
5 | import retrofit2.Call;
6 | import retrofit2.http.GET;
7 |
8 | public interface OTARepoClientInterface {
9 | @GET("repo/latest-release/")
10 | Call getLatestRelease();
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/updateManager/OTARestClient.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.updateManager;
2 |
3 |
4 | import retrofit2.Retrofit;
5 | import retrofit2.converter.gson.GsonConverterFactory;
6 |
7 | public class OTARestClient {
8 | public static final String BASE_URL = "http://avi.x1unix.com";
9 | private static Retrofit retrofit = null;
10 |
11 | public static Retrofit getClient() {
12 | if (retrofit==null) {
13 | retrofit = new Retrofit.Builder()
14 | .baseUrl(BASE_URL)
15 | .addConverterFactory(GsonConverterFactory.create())
16 | .build();
17 | }
18 | return retrofit;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/updateManager/OTAStateListener.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.updateManager;
2 |
3 | import com.x1unix.avi.model.AviSemVersion;
4 |
5 | public class OTAStateListener {
6 | protected void onUpdateAvailable(AviSemVersion availableVersion, AviSemVersion currentVersion) {
7 |
8 | }
9 |
10 | protected void onUpdateMissing(AviSemVersion availableVersion, AviSemVersion currentVersion) {
11 |
12 | }
13 |
14 | protected void onError(Throwable t) {
15 |
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/updateManager/OTAUpdateChecker.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.updateManager;
2 |
3 | import android.app.Activity;
4 | import android.app.AlertDialog;
5 | import android.content.Context;
6 | import android.content.DialogInterface;
7 | import android.content.Intent;
8 | import android.content.res.Resources;
9 | import android.net.Uri;
10 |
11 | import retrofit2.Call;
12 | import retrofit2.Callback;
13 | import retrofit2.Response;
14 |
15 | import com.rollbar.android.Rollbar;
16 | import com.x1unix.avi.R;
17 | import com.x1unix.avi.UpdateDownloaderActivity;
18 | import com.x1unix.avi.model.AviSemVersion;
19 |
20 | public class OTAUpdateChecker {
21 | public static void checkForUpdates(final OTAStateListener otaEventListener, final boolean allowNightlies) {
22 | OTARepoClientInterface repoClient = OTARestClient.getClient().create(OTARepoClientInterface.class);
23 | Call call = repoClient.getLatestRelease();
24 | call.enqueue(new Callback() {
25 | @Override
26 | public void onResponse(Callcall, Response response) {
27 | int statusCode = response.code();
28 | try {
29 | AviSemVersion receivedVersion = response.body();
30 | AviSemVersion current = AviSemVersion.getApplicationVersion();
31 |
32 | boolean isNew = false;
33 |
34 | try {
35 | isNew = BuildParser.compareBuild(receivedVersion.getReleaseDate());
36 | } catch(Exception ex) {
37 | isNew = true;
38 | }
39 |
40 | boolean isStable = receivedVersion.isStable();
41 | boolean isSuitable = (isStable || allowNightlies);
42 |
43 | if (isNew && isSuitable) {
44 | otaEventListener.onUpdateAvailable(receivedVersion, current);
45 | } else {
46 | otaEventListener.onUpdateMissing(receivedVersion, current);
47 | }
48 | } catch (Exception ex) {
49 | otaEventListener.onError(ex);
50 | }
51 | }
52 |
53 | @Override
54 | public void onFailure(Callcall, Throwable t) {
55 | // Log error here since request failed
56 | otaEventListener.onError(t);
57 | }
58 | });
59 | }
60 |
61 | public static AlertDialog.Builder makeDialog(final Context owner, final AviSemVersion newVer) {
62 | Resources res = owner.getResources();
63 | AlertDialog.Builder dialInstallUpdate = new AlertDialog.Builder(owner);
64 | String modConfimText = res.getString(R.string.upd_confirm);
65 | modConfimText = modConfimText.replace("@version", newVer.toString());
66 |
67 | dialInstallUpdate.setMessage(modConfimText);
68 | dialInstallUpdate.setTitle(res.getString(R.string.upd_new_available))
69 | .setCancelable(false)
70 | .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
71 | public void onClick(DialogInterface dialog, int id) {
72 | dialog.cancel();
73 | }
74 | });
75 |
76 | return dialInstallUpdate;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/webplayer/AviWebView.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.webplayer;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.os.Handler;
6 | import android.os.Looper;
7 | import android.util.AttributeSet;
8 | import android.util.Log;
9 | import android.webkit.WebChromeClient;
10 | import android.webkit.WebView;
11 |
12 | import java.util.Map;
13 |
14 | /**
15 | * This class serves as a WebView to be used in conjunction with a VideoEnabledWebChromeClient.
16 | * It makes possible:
17 | * - To detect the HTML5 video ended event so that the VideoEnabledWebChromeClient can exit full-screen.
18 | *
19 | * Important notes:
20 | * - Javascript is enabled by default and must not be disabled with getSettings().setJavaScriptEnabled(false).
21 | * - setWebChromeClient() must be called before any loadData(), loadDataWithBaseURL() or loadUrl() method.
22 | *
23 | * @author Cristian Perez (http://cpr.name)
24 | *
25 | */
26 | public class AviWebView extends WebView
27 | {
28 | public class JavascriptInterface
29 | {
30 | @android.webkit.JavascriptInterface @SuppressWarnings("unused")
31 | public void notifyVideoEnd() // Must match Javascript interface method of VideoEnabledWebChromeClient
32 | {
33 | Log.d("___", "GOT IT");
34 | // This code is not executed in the UI thread, so we must force that to happen
35 | new Handler(Looper.getMainLooper()).post(new Runnable()
36 | {
37 | @Override
38 | public void run()
39 | {
40 | if (aviWebChromeClient != null)
41 | {
42 | aviWebChromeClient.onHideCustomView();
43 | }
44 | }
45 | });
46 | }
47 | }
48 |
49 | private AviWebChromeClient aviWebChromeClient;
50 | private boolean addedJavascriptInterface;
51 |
52 | @SuppressWarnings("unused")
53 | public AviWebView(Context context)
54 | {
55 | super(context);
56 | addedJavascriptInterface = false;
57 | }
58 |
59 | @SuppressWarnings("unused")
60 | public AviWebView(Context context, AttributeSet attrs)
61 | {
62 | super(context, attrs);
63 | addedJavascriptInterface = false;
64 | }
65 |
66 | @SuppressWarnings("unused")
67 | public AviWebView(Context context, AttributeSet attrs, int defStyle)
68 | {
69 | super(context, attrs, defStyle);
70 | addedJavascriptInterface = false;
71 | }
72 |
73 | /**
74 | * Indicates if the video is being displayed using a custom view (typically full-screen)
75 | * @return true it the video is being displayed using a custom view (typically full-screen)
76 | */
77 | @SuppressWarnings("unused")
78 | public boolean isVideoFullscreen()
79 | {
80 | return aviWebChromeClient != null && aviWebChromeClient.isVideoFullscreen();
81 | }
82 |
83 | /**
84 | * Pass only a VideoEnabledWebChromeClient instance.
85 | */
86 | @Override @SuppressLint("SetJavaScriptEnabled")
87 | public void setWebChromeClient(WebChromeClient client)
88 | {
89 | getSettings().setJavaScriptEnabled(true);
90 |
91 | if (client instanceof AviWebChromeClient)
92 | {
93 | this.aviWebChromeClient = (AviWebChromeClient) client;
94 | }
95 |
96 | super.setWebChromeClient(client);
97 | }
98 |
99 | @Override
100 | public void loadData(String data, String mimeType, String encoding)
101 | {
102 | addJavascriptInterface();
103 | super.loadData(data, mimeType, encoding);
104 | }
105 |
106 | @Override
107 | public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)
108 | {
109 | addJavascriptInterface();
110 | super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
111 | }
112 |
113 | @Override
114 | public void loadUrl(String url)
115 | {
116 | addJavascriptInterface();
117 | super.loadUrl(url);
118 | }
119 |
120 | @Override
121 | public void loadUrl(String url, Map additionalHttpHeaders)
122 | {
123 | addJavascriptInterface();
124 | super.loadUrl(url, additionalHttpHeaders);
125 | }
126 |
127 | private void addJavascriptInterface()
128 | {
129 | if (!addedJavascriptInterface)
130 | {
131 | // Add javascript interface to be called when the video ends (must be done before page load)
132 | //noinspection all
133 | addJavascriptInterface(new JavascriptInterface(), "_VideoEnabledWebView"); // Must match Javascript interface name of VideoEnabledWebChromeClient
134 |
135 | addedJavascriptInterface = true;
136 | }
137 | }
138 |
139 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/x1unix/avi/webplayer/AviWebViewClient.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi.webplayer;
2 |
3 | import android.annotation.TargetApi;
4 | import android.os.Build;
5 | import android.util.Log;
6 | import android.webkit.WebResourceResponse;
7 | import android.webkit.WebView;
8 | import android.webkit.WebViewClient;
9 |
10 | import com.x1unix.avi.helpers.AdBlocker;
11 |
12 | import java.util.HashMap;
13 | import java.util.Map;
14 |
15 | public class AviWebViewClient extends WebViewClient {
16 | private String LSECTION = AviWebViewClient.class.getName();
17 | private Map loadedUrls = new HashMap<>();
18 | private String currentUrl = "";
19 | private boolean disableAds = false;
20 |
21 | public AviWebViewClient(boolean blockAds) {
22 | super();
23 | disableAds = blockAds;
24 | }
25 |
26 | @Override
27 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
28 | Log.w(LSECTION, "Client has tried to redirect to '" + url + "'");
29 | return true;
30 | }
31 |
32 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
33 | @Override
34 | public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
35 | // Do nothing if adblock disabled
36 | if (!disableAds) return super.shouldInterceptRequest(view, url);
37 |
38 | boolean ad;
39 | if (!loadedUrls.containsKey(url)) {
40 | ad = AdBlocker.isAd(url);
41 | loadedUrls.put(url, ad);
42 | } else {
43 | ad = loadedUrls.get(url);
44 | };
45 | return ad ? AdBlocker.createEmptyResource("text/javascript") : super.shouldInterceptRequest(view, url);
46 | }
47 |
48 | public void onPageStarted (WebView view, String url)
49 | {
50 | if (url != currentUrl) {
51 | // stop loading page if its not the originalurl.
52 | Log.w(LSECTION, "Page loading prevented");
53 | view.stopLoading();
54 | }
55 | }
56 |
57 | public void updateCurrentUrl(String newUrl) {
58 | currentUrl = newUrl;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v22/ic_bookmark_full_wrapped.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v22/ic_bookmark_wrapped.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/avi_r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x1unix/Avi/b9c2002b3953ebfe51c93f19fa9c67415c6f93b6/app/src/main/res/drawable/avi_r.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/avi_wide_r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x1unix/Avi/b9c2002b3953ebfe51c93f19fa9c67415c6f93b6/app/src/main/res/drawable/avi_wide_r.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/block_rounded.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/border_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | -
13 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/effect_ripple.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | -
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_avi.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_avi_wide.xml:
--------------------------------------------------------------------------------
1 |
6 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark_full.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark_full_wrapped.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark_gray.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bookmark_wrapped.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cloud_off_black.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_error.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_restore_gray.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_gray.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/no_poster.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x1unix/Avi/b9c2002b3953ebfe51c93f19fa9c67415c6f93b6/app/src/main/res/drawable/no_poster.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/progress_drawable.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | -
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/splash_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | -
7 |
10 |
11 | -
12 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/star.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/list_item_movie.xml:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
31 |
32 |
39 |
40 |
41 |
56 |
57 |
68 |
69 |
74 |
82 |
83 |
91 |
92 |
105 |
106 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_dashboard.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
20 |
21 |
28 |
29 |
30 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_movie_player.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
23 |
24 |
25 |
36 |
41 |
52 |
59 |
70 |
71 |
72 |
80 |
81 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_support.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_update_downloader.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
18 |
19 |
20 |
26 |
35 |
36 |
44 |
45 |
46 |
50 |
51 |
59 |
60 |
61 |
69 |
77 |
87 |
88 |
89 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_movie.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
29 |
30 |
37 |
38 |
47 |
48 |
62 |
63 |
73 |
74 |
79 |
87 |
88 |
97 |
98 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tab_favorites.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
21 |
22 |
33 |
34 |
35 |
40 |
41 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/tab_history.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
21 |
22 |
33 |
34 |
39 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_loading_video.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
19 |
20 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
13 |
14 |
25 |
26 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_movie_details.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/search_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x1unix/Avi/b9c2002b3953ebfe51c93f19fa9c67415c6f93b6/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x1unix/Avi/b9c2002b3953ebfe51c93f19fa9c67415c6f93b6/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x1unix/Avi/b9c2002b3953ebfe51c93f19fa9c67415c6f93b6/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x1unix/Avi/b9c2002b3953ebfe51c93f19fa9c67415c6f93b6/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x1unix/Avi/b9c2002b3953ebfe51c93f19fa9c67415c6f93b6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 30sp
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-port-v21/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0dp
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Поиск фильмов и сериалов
4 | Требуется подключение к Интернету.
5 | Для поиска и просмотра фильмов, необходимо стабильное подключение к сети.
6 | Не удалось выполнить поиск
7 | Требуется подключение к Интернету
8 | По этому запросу ничего не найдено.
9 | Настройки
10 | Помощь
11 | Обновить
12 | Подождите пожалуйста…
13 | Функция будет доступна в будущих релизах
14 | При последнем запросе к серверу произошла ошибка. Попробуйте другой запрос или повторите позже.
15 |
16 |
17 | Видео
18 | О Приложении
19 | Обновления
20 | Блокировать рекламу
21 | Версия
22 | Автор
23 | Обратная связь
24 | Проверить сейчас
25 | Проверять автоматически
26 | Использовать устаревший видеоплеер
27 |
28 |
29 | Поиск обновлений
30 | Обновления не найдены
31 | Ошибка при получении информации с репозитория
32 | Доступно новое обновление
33 | Доступна новая версия: @version \nЗагрузить новую версию?
34 |
35 |
36 | Отключить рекламу перед просмотром видео. Рекомендуется менять при возникновении проблем с проигрыванием видео.
37 | Разрешить приложению автоматически проверять обновления.
38 | Использовать обычный HTML5 плеер. Включите эту опцию если у вас возникают проблемы с проигрыванием видео.
39 |
40 |
41 | Настройки
42 |
43 |
44 | Смотреть
45 | Актеры и создатели
46 | Актеры
47 | Режиссеры
48 | Продюсеры
49 | Возраст. ограничения
50 | Год выпуска
51 | Продолжительность
52 | Жанр
53 | Добавить в избранное
54 | Удалить из избранного
55 | Постер к фильму
56 | Ошибка при получении информации о фильме
57 | Загрузка
58 |
59 | Поиск
60 | Ничего не найдено
61 | Предлагать нестабильные версии
62 | Нестабильные сборки приложения включают в себя самые новые функции и возможности, но могут содержать ошибки.
63 |
64 | Элемент добавлен в избранное
65 | Элемент удален из избранного
66 |
67 | Избранное
68 | Недавние
69 | Здесь появятся фильмы и сериалы, как только вы добавите их в Избранное
70 | Здесь появятся просмотренные вами фильмы и сериалы
71 | В Избранном
72 | В Избранное
73 | Загрузка обновления
74 | Подготовка к загрузке
75 | Установка пакета
76 | Готово
77 | Ошибка
78 | Не удалось загрузить обновление:\n
79 | Нету прав чтения/записи для папки загрузки
80 | Установить
81 | Предварительная сборка
82 | Номер сборки
83 |
84 |
85 | Показать детали
86 | Удалить из %PLAYLIST%
87 | Воспроизвести
88 |
89 |
90 | избранного
91 | списка
92 |
93 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw600dp-land/props.xml:
--------------------------------------------------------------------------------
1 |
2 | true
3 | 5
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw600dp/props.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | 3
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 128dp
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw720dp-land/props.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | 7
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw720dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 20sp
4 | 8sp
5 | 19sp
6 | 18sp
7 | 20dp
8 | 6sp
9 | 25dp
10 | 18dp
11 |
12 | 30sp
13 | 21sp
14 | 18sp
15 | 250sp
16 | 60sp
17 | 52sp
18 |
19 | 18sp
20 | 16sp
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values-uk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Для пошуку та перегляду фільмів необхідне підключення до Інтернету
4 | При останному запиті до серверу сталась помилка. Спробуйте інший запит або спробуйте пізніше
5 | Необхідне підключення до Інтернету
6 | Не вдалося виконати пошук
7 | Необхідне підключення до Інтернету
8 | Пошук фільмів та серіалів
9 | За цим запитом нічого не знайдено.
10 | Налаштування
11 | Допомога
12 | Оновити
13 | Зачекайте будь-ласка…
14 | Функція буде доступна в майбутніх релізах
15 |
16 |
17 | Відео
18 | Про додаток
19 | Оновлення
20 | Блокувати рекламу
21 | Версія
22 | Автор
23 | Зворотній зв\'язок
24 | Перевірити зараз
25 | Перевіряти автоматично
26 | Використовувати застарілий відеоплеєр
27 |
28 |
29 | Пошук оновлень
30 | Оновлення не знайдені
31 | Помилка при отриманні інформації з репозиторію
32 | Доступне нове оновленняе
33 | Доступна нова версія: @version \nЗавантажити нову версію?
34 |
35 |
36 | Відключити рекламу перед переглядом кіно. Рекомендується міняти при виникненні проблем з програванням відео.
37 | Дозволити додатку автоматично перевіряти оновлення.
38 | Використовувати звичайний HTML5 плеєр. Ввімкніть цю опцію, якщо у вас виникають проблеми з програванням відео
39 |
40 |
41 | Налаштування
42 |
43 |
44 | Дивитися
45 | Актори та творці
46 | Актори
47 | Режисери
48 | Продюсери
49 | Вікові обмеження
50 | Рік випуску
51 | Тривалість
52 | Жанр
53 | Додати в обране
54 | Видалити з обраного
55 | Постер
56 | Помилка при отриманні інформації про фільм
57 | Завантаження
58 |
59 | Пошук
60 | Нічого не знайдено
61 | Пропонувати нестабільні версії
62 | Нестабільні збірки включають в себе найновіші функції і можливості, але можуть містити помилки.
63 |
64 | Елемент доданий в обране
65 | Елемент видалений з обраного
66 |
67 | Обране
68 | Недавні
69 | Тут з\'являться фільми і серіали, як тільки ви додасте їх в Вибране
70 | Тут з\'являться переглянуті вами фільми й серіали
71 | В Обране
72 | В Обраному
73 | Завантаження оновлення
74 | Підготовка до завантаження
75 | Установка пакета
76 | Готово
77 | Помилка
78 | Не вдалося завантажити оновлення:\n
79 | Нема прав читання / запису для папки завантаження
80 | Встановити
81 | Попередня збірка
82 | Номер Збірки
83 |
84 |
85 |
86 | Детальніше
87 | Видалити з %PLAYLIST%
88 | Відтворити
89 |
90 |
91 | обраного
92 | списку
93 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #111
4 | #000
5 | #999
6 |
7 | #FF3909
8 | #00b482
9 |
10 | #555555
11 | #f6f6f6
12 | #707070
13 | #8A8A8A
14 |
15 | #66000000
16 | #FAFAFA
17 | #bbb
18 |
19 | #605F61
20 | #1C1C1C
21 | #FAFAFA
22 |
23 | #FF000000
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 | 16dp
7 |
8 | 16dp
9 | 180dp
10 | 16dp
11 | 100dp
12 | 180sp
13 | 16sp
14 | 5sp
15 | 14sp
16 | 20dp
17 | 14sp
18 | 4sp
19 | 20dp
20 | 12dp
21 | 25sp
22 | 16sp
23 | 14sp
24 | 210sp
25 | 40sp
26 | 32sp
27 |
28 |
29 | 14sp
30 | 10sp
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/values/keys.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | prop_no_ads
6 | prop_autocheck_updates
7 | prop_allow_unstable
8 | prop_btn_update_now
9 | prop_use_legacy_player
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/props.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 | 1
5 | false
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Avi
4 | Search movies and TV-shows
5 | Failed to get search results
6 | Internet connection required to do this
7 | No Network Connection
8 | An error occurred during last query. Please try another query or try again later.
9 | Internet connection required to search and watch movies.
10 | No items found, try another query.
11 | Settings
12 | Help
13 | Refresh
14 | Please wait…
15 | Feature will be available on future releases.
16 | Avi Movie Player
17 |
18 |
19 | Video
20 | About
21 | Updates
22 | Block Ads
23 | App Version
24 | Author
25 | Contact
26 | Check now
27 | Check automatically
28 | Use legacy video player
29 |
30 |
31 | Searching for updates
32 | No updates found
33 | Failed to get information from repository
34 | New Update Available
35 | New available version: @version \nDo you want to install it?
36 |
37 |
38 | Disable pre-roll ads. Disable this is you have issue with movie player.
39 | Allow to application to check for updates automatically on background
40 | Use regular HTML5 video-player. Turn this on if you have some issues with playback
41 |
42 |
43 | avi-app@x1unix.com
44 | Settings
45 |
46 |
47 | Watch
48 | Actors And Creators
49 | Actors
50 | Directors
51 | Producers
52 | Age Restrictions
53 | Release Year
54 | Length
55 | Genre
56 | Add to bookmarks
57 | Remove from bookmarks
58 | Movie poster
59 | Failed to get movie information
60 | Loading
61 |
62 | Search for
63 | Nothing found
64 | Allow unstable versions
65 | Unstable versions includes the latest features, but may have issues and errors.
66 |
67 | Element added to favorites
68 | Element removed from favorites
69 | Favorites
70 | Recently viewed
71 | There will be movies and TV shows as soon as you add them to Favorites
72 | There will be movies and series you watched
73 | In Favorites
74 | Add to Favorites
75 | Downloading update
76 | Preparing for download
77 | Installing package
78 | Done
79 | Error
80 | Failed to download update:\n
81 | No permissions to read/write for download directory
82 | Install
83 | Preview version
84 | Build Number
85 |
86 |
87 | Show details
88 | Remove from %PLAYLIST%
89 | Open in player
90 |
91 |
92 | favorites
93 | list
94 |
95 |
96 | \@x1unix, 2017
97 |
98 |
99 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
34 |
35 |
38 |
39 |
46 |
47 |
49 |
50 |
54 |
55 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/xml-v14/pref_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
23 |
26 |
27 |
32 |
33 |
38 |
39 |
40 |
42 |
46 |
47 |
51 |
52 |
56 |
57 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
23 |
26 |
27 |
32 |
33 |
38 |
39 |
40 |
42 |
46 |
47 |
51 |
52 |
56 |
57 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/search_widget_provider.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/searchable.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/app/src/test/java/com/x1unix/avi/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.x1unix.avi;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | ACCESS_TOKEN=286659d0df564dfe996e17c7f45268dd
2 | ENVIRONMENT=production
3 | LOCAL_USERNAME=`whoami`
4 | REVISION=`git log -n 1 --pretty=format:"%H"`
5 |
6 | if [ "$TRAVIS_BRANCH" == "prod" ]; then
7 | curl https://api.rollbar.com/api/1/deploy/ \
8 | -F access_token=$ACCESS_TOKEN \
9 | -F environment=$ENVIRONMENT \
10 | -F revision=$REVISION \
11 | -F local_username=$LOCAL_USERNAME
12 | fi
13 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/x1unix/Avi/b9c2002b3953ebfe51c93f19fa9c67415c6f93b6/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/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 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------