├── .github
└── workflows
│ └── android.yml
├── .gitignore
├── COPYING
├── README.md
├── app
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── debug
│ └── res
│ │ ├── mipmap-anydpi-v26
│ │ └── ic_launcher.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_foreground.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_foreground.png
│ │ └── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_foreground.png
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── redcoracle
│ │ └── episodes
│ │ ├── AboutActivity.java
│ │ ├── AddShowPreviewActivity.java
│ │ ├── AddShowPreviewFragment.java
│ │ ├── AddShowSearchActivity.java
│ │ ├── AddShowSearchFragment.java
│ │ ├── AddShowSearchResults.java
│ │ ├── AutoRefreshHelper.java
│ │ ├── EpisodeActivity.java
│ │ ├── EpisodeDetailsFragment.java
│ │ ├── EpisodesApplication.java
│ │ ├── EpisodesCounter.java
│ │ ├── EpisodesListFragment.java
│ │ ├── FileUtilities.java
│ │ ├── MainActivity.java
│ │ ├── NextEpisodeFragment.java
│ │ ├── Preferences.java
│ │ ├── RefreshShowUtil.java
│ │ ├── SeasonActivity.java
│ │ ├── SeasonsListFragment.java
│ │ ├── SelectBackupDialog.java
│ │ ├── SettingsActivity.java
│ │ ├── SettingsFragment.java
│ │ ├── ShowActivity.java
│ │ ├── ShowDetailsFragment.java
│ │ ├── ShowNotesFragment.java
│ │ ├── ShowsListFragment.java
│ │ ├── db
│ │ ├── DatabaseOpenHelper.java
│ │ ├── EpisodesTable.java
│ │ ├── ShowsProvider.java
│ │ └── ShowsTable.java
│ │ ├── services
│ │ ├── AddShowTask.java
│ │ ├── AsyncTask.java
│ │ ├── BackupTask.java
│ │ ├── DeleteShowTask.java
│ │ ├── RefreshAllShowsTask.java
│ │ ├── RefreshShowService.java
│ │ ├── RefreshShowTask.java
│ │ └── RestoreTask.java
│ │ ├── tvdb
│ │ ├── Client.java
│ │ ├── Episode.java
│ │ ├── GetEpisodesParser.java
│ │ ├── GetShowParser.java
│ │ ├── SearchShowsParser.java
│ │ └── Show.java
│ │ └── widget
│ │ ├── ObservableScrollView.java
│ │ ├── WrapContentListView.java
│ │ └── WrapContentViewPager.java
│ └── res
│ ├── color
│ └── tab_text.xml
│ ├── drawable-hdpi
│ ├── ic_menu_add_show.png
│ ├── ic_menu_filter_shows_list.png
│ └── shows_list_gradient.xml
│ ├── drawable-mdpi
│ ├── ic_menu_add_show.png
│ └── ic_menu_filter_shows_list.png
│ ├── drawable-nodpi
│ └── blank_show_banner.png
│ ├── drawable-xhdpi
│ ├── ic_menu_add_show.png
│ └── ic_menu_filter_shows_list.png
│ ├── drawable-xxhdpi
│ ├── ic_menu_add_show.png
│ └── ic_menu_filter_shows_list.png
│ ├── drawable
│ ├── archived_toggle.xml
│ ├── gradient.xml
│ ├── ic_show_archived.xml
│ ├── ic_show_starred.xml
│ ├── ic_show_unarchived.xml
│ ├── ic_show_unstarred.xml
│ ├── starred_toggle.xml
│ └── watched_progress.xml
│ ├── layout
│ ├── about_activity.xml
│ ├── add_show_preview_activity.xml
│ ├── add_show_preview_fragment.xml
│ ├── add_show_search_activity.xml
│ ├── add_show_search_fragment.xml
│ ├── add_show_search_results_list_item.xml
│ ├── episode_activity.xml
│ ├── episode_details_fragment.xml
│ ├── episodes_list_fragment.xml
│ ├── episodes_list_item.xml
│ ├── main_activity.xml
│ ├── season_activity.xml
│ ├── seasons_list_fragment.xml
│ ├── seasons_list_item.xml
│ ├── settings_activity.xml
│ ├── show_activity.xml
│ ├── show_details_fragment.xml
│ ├── show_notes_fragment.xml
│ ├── shows_list_fragment.xml
│ └── shows_list_item.xml
│ ├── menu
│ ├── add_show_preview_fragment.xml
│ ├── main.xml
│ ├── season_activity.xml
│ ├── show_activity.xml
│ └── shows_list_fragment.xml
│ ├── mipmap-anydpi-v26
│ └── ic_launcher.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ └── ic_launcher_foreground.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ └── ic_launcher_foreground.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ └── ic_launcher_foreground.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ └── ic_launcher_foreground.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_background.png
│ └── ic_launcher_foreground.png
│ ├── values-bg
│ └── strings.xml
│ ├── values-cs
│ └── strings.xml
│ ├── values-de
│ └── strings.xml
│ ├── values-eo
│ └── strings.xml
│ ├── values-es
│ └── strings.xml
│ ├── values-eu
│ └── strings.xml
│ ├── values-fr
│ └── strings.xml
│ ├── values-hr
│ └── strings.xml
│ ├── values-it
│ └── strings.xml
│ ├── values-nb-rNO
│ └── strings.xml
│ ├── values-ru
│ └── strings.xml
│ ├── values-sv
│ └── strings.xml
│ ├── values-tr
│ └── strings.xml
│ ├── values-v14
│ └── styles.xml
│ ├── values
│ ├── arrays.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── themes.xml
│ └── xml
│ └── preferences.xml
├── assets
├── feature-graphic.png
├── hi-res-icon.png
├── screenshot-1.png
├── screenshot-2.png
└── screenshot-3.png
├── build.gradle
├── fastlane
└── metadata
│ └── android
│ └── en-US
│ ├── changelogs
│ ├── 0014.txt
│ ├── 0015.txt
│ ├── 0016.txt
│ ├── 0017.txt
│ ├── 0018.txt
│ ├── 0019.txt
│ ├── 0020.txt
│ ├── 0021.txt
│ ├── 0022.txt
│ ├── 0023.txt
│ ├── 0024.txt
│ └── 0025.txt
│ ├── full_description.txt
│ ├── images
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── 5.png
│ │ └── 6.png
│ ├── short_description.txt
│ └── title.txt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | test:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v4
10 | - name: Setup JDK
11 | uses: actions/setup-java@v4
12 | with:
13 | distribution: 'temurin'
14 | java-version: '17'
15 | - name: Test with Gradle
16 | run: ./gradlew test
17 |
18 | build:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - uses: actions/checkout@v4
22 | - name: Setup JDK
23 | uses: actions/setup-java@v4
24 | with:
25 | distribution: 'temurin'
26 | java-version: '17'
27 | - name: Verify Gradle
28 | uses: gradle/actions/wrapper-validation@v4
29 | - name: Build with Gradle
30 | run: ./gradlew build
31 | - name: Upload APK
32 | uses: actions/upload-artifact@v4
33 | with:
34 | name: app-debug
35 | path: app/build/outputs/apk/standard/debug/app-standard-debug.apk
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | .gradle/
3 | local.properties
4 | .idea/
5 | *.iml
6 | app/fdroid/
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Episodes
2 | 
3 | [](https://hosted.weblate.org/engage/episodes/)
4 | [](https://f-droid.org/en/packages/com.redcoracle.episodes)
5 |
6 | Keep track of which episodes you've watched of your favourite shows.
7 |
8 | This product uses the [TMDB](https://www.themoviedb.org) API but is not endorsed or certified by TMDB.
9 |
10 | ## Contributing
11 |
12 | Contributions are very welcome. Please file bugs, fork the repository, [translate](https://hosted.weblate.org/projects/episodes/) and send pull requests.
13 |
14 | ## License
15 |
16 | Copylefted libre software licensed [GPLv3](http://www.gnu.org/licenses/gpl-3.0.txt)+.
17 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | def getCommitId = { ->
4 | def gitOutput = new ByteArrayOutputStream()
5 | exec {
6 | commandLine 'git', 'rev-parse', '--short', 'HEAD'
7 | standardOutput = gitOutput
8 | }
9 | return gitOutput.toString().trim()
10 | }
11 |
12 | android {
13 | namespace 'com.redcoracle.episodes'
14 | compileSdkVersion 33
15 | defaultConfig {
16 | minSdkVersion 21
17 | targetSdkVersion 33
18 | versionCode 25
19 | versionName "0.16.1"
20 | buildConfigField "String", "TMDB_KEY", "\"1553d2e4fa2912fc0953305d4d3e7c44\""
21 | buildConfigField "String", "GIT_COMMIT_ID", "\"${getCommitId()}\""
22 | }
23 | flavorDimensions "flavor"
24 | productFlavors {
25 | standard {
26 | dimension "flavor"
27 | applicationId = "com.redcoracle.episodes"
28 | }
29 | }
30 | buildTypes {
31 | debug {
32 | applicationIdSuffix '.debug'
33 | versionNameSuffix '-DEBUG'
34 | multiDexEnabled true
35 | }
36 | release {
37 | minifyEnabled true
38 | shrinkResources true
39 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
40 | }
41 | }
42 | lint {
43 | abortOnError false
44 | }
45 | compileOptions {
46 | sourceCompatibility = 1.8
47 | targetCompatibility = 1.8
48 | }
49 | if (project.hasProperty('signingStoreLocation') &&
50 | project.hasProperty('signingStorePassword') &&
51 | project.hasProperty('signingKeyAlias') &&
52 | project.hasProperty('signingKeyPassword')) {
53 | println "Found sign properties in gradle.properties! Signing build…"
54 |
55 | signingConfigs {
56 | release {
57 | storeFile file(signingStoreLocation)
58 | storePassword signingStorePassword
59 | keyAlias signingKeyAlias
60 | keyPassword signingKeyPassword
61 | }
62 | }
63 |
64 | buildTypes.release.signingConfig = signingConfigs.release
65 | } else {
66 | buildTypes.release.signingConfig = null
67 | }
68 | }
69 |
70 | dependencies {
71 | implementation fileTree(include: ['*.jar'], dir: 'libs')
72 | implementation 'androidx.appcompat:appcompat:1.4.2'
73 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
74 | implementation 'androidx.preference:preference:1.2.0'
75 | implementation 'androidx.recyclerview:recyclerview:1.2.1'
76 | implementation 'com.google.android.material:material:1.6.1'
77 | implementation 'com.github.bumptech.glide:glide:4.14.1'
78 | implementation 'com.uwetrottmann.tmdb2:tmdb-java:2.8.1'
79 | implementation 'org.apache.commons:commons-collections4:4.4'
80 | debugImplementation 'com.android.support:multidex:2.0.1'
81 | annotationProcessor 'com.github.bumptech.glide:compiler:4.14.1'
82 | }
83 |
--------------------------------------------------------------------------------
/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 /opt/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 | # Glide
13 | -keep public class * implements com.bumptech.glide.module.GlideModule
14 | -keep public class * extends com.bumptech.glide.module.AppGlideModule
15 | -keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
16 | **[] $VALUES;
17 | public *;
18 | }
19 |
20 | # TMDB
21 | -keep class com.uwetrottmann.tmdb2.entities.** { *; }
22 | -keep class com.uwetrottmann.tmdb2.enumerations.** { *; }
23 |
24 | # OkHttp platform used only on JVM and when Conscrypt and other security providers are available.
25 | -dontwarn okhttp3.internal.platform.**
26 | -dontwarn org.conscrypt.**
27 | -dontwarn org.bouncycastle.**
28 | -dontwarn org.openjsse.**
29 |
30 | # R8 said to add these
31 | -dontwarn kotlin.coroutines.Continuation
32 |
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
33 |
36 |
37 |
38 |
41 |
42 |
43 |
46 |
47 |
48 |
51 |
52 |
53 |
57 |
58 |
59 |
62 |
63 |
64 |
67 |
68 |
69 |
71 |
72 |
73 |
76 |
77 |
78 |
79 |
80 |
81 |
85 |
86 |
87 |
88 |
89 |
90 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/AboutActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.os.Bundle;
21 | import android.view.MenuItem;
22 | import android.widget.TextView;
23 |
24 | import androidx.appcompat.app.AppCompatActivity;
25 |
26 | public class AboutActivity
27 | extends AppCompatActivity
28 | {
29 | @Override
30 | public void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 |
33 | setContentView(R.layout.about_activity);
34 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
35 |
36 | TextView versionInfoView = findViewById(R.id.version_view);
37 | versionInfoView.setText(
38 | getBaseContext().getString(
39 | R.string.version,
40 | BuildConfig.VERSION_NAME,
41 | BuildConfig.GIT_COMMIT_ID));
42 | }
43 |
44 | @Override
45 | public boolean onOptionsItemSelected(MenuItem item) {
46 | switch (item.getItemId()) {
47 | case android.R.id.home:
48 | finish();
49 | return true;
50 |
51 | default:
52 | return super.onOptionsItemSelected(item);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/AddShowPreviewActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.content.Intent;
21 | import android.os.Bundle;
22 | import android.view.MenuItem;
23 |
24 | import androidx.appcompat.app.AppCompatActivity;
25 | import androidx.fragment.app.FragmentTransaction;
26 |
27 | import com.redcoracle.episodes.tvdb.Show;
28 |
29 | import java.util.List;
30 |
31 | public class AddShowPreviewActivity
32 | extends AppCompatActivity
33 | {
34 | @Override
35 | public void onCreate(Bundle savedInstanceState)
36 | {
37 | super.onCreate(savedInstanceState);
38 |
39 | setContentView(R.layout.add_show_preview_activity);
40 |
41 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
42 |
43 | Intent intent = getIntent();
44 | int searchResultIndex = intent.getIntExtra("searchResultIndex", 0);
45 |
46 | AddShowSearchResults results = AddShowSearchResults.getInstance();
47 | List resultsData = results.getData();
48 |
49 | // Ensure that there is actually data to display,
50 | // because Android may have destroyed it.
51 | if (resultsData == null) {
52 | // Android has killed the singleton instance which held the
53 | // data. There's nothing this activity can do, so finish.
54 | finish();
55 | return;
56 | }
57 |
58 | Show show = resultsData.get(searchResultIndex);
59 | getSupportActionBar().setTitle(show.getName());
60 |
61 | // If this is the first time the activity has been created,
62 | // create and add the preview fragment.
63 | if (savedInstanceState == null) {
64 | AddShowPreviewFragment fragment =
65 | AddShowPreviewFragment.newInstance(searchResultIndex);
66 | FragmentTransaction transaction =
67 | getSupportFragmentManager().beginTransaction();
68 | transaction.add(R.id.preview_fragment_container, fragment);
69 | transaction.commit();
70 | }
71 | }
72 |
73 | @Override
74 | public boolean onOptionsItemSelected(MenuItem item) {
75 | switch (item.getItemId()) {
76 | case android.R.id.home:
77 | finish();
78 | return true;
79 |
80 | default:
81 | return super.onOptionsItemSelected(item);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/AddShowPreviewFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.os.Bundle;
21 | import android.view.LayoutInflater;
22 | import android.view.Menu;
23 | import android.view.MenuInflater;
24 | import android.view.MenuItem;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 | import android.widget.TextView;
28 |
29 | import androidx.fragment.app.Fragment;
30 |
31 | import com.redcoracle.episodes.services.AddShowTask;
32 | import com.redcoracle.episodes.services.AsyncTask;
33 | import com.redcoracle.episodes.tvdb.Show;
34 |
35 | import java.text.DateFormat;
36 | import java.util.Date;
37 | import java.util.List;
38 |
39 | public class AddShowPreviewFragment
40 | extends Fragment
41 | {
42 | private Show show;
43 |
44 | public static AddShowPreviewFragment newInstance(int searchResultIndex) {
45 | AddShowPreviewFragment instance = new AddShowPreviewFragment();
46 |
47 | Bundle args = new Bundle();
48 | args.putInt("searchResultIndex", searchResultIndex);
49 |
50 | instance.setArguments(args);
51 | return instance;
52 | }
53 |
54 | public void onCreate(Bundle savedInstanceState) {
55 | super.onCreate(savedInstanceState);
56 | setHasOptionsMenu(true);
57 | }
58 |
59 | @Override
60 | public View onCreateView(LayoutInflater inflater,
61 | ViewGroup container,
62 | Bundle savedInstanceState) {
63 | View view = inflater.inflate(R.layout.add_show_preview_fragment,
64 | container,
65 | false);
66 |
67 | TextView overviewView = (TextView)view.findViewById(R.id.overview);
68 | TextView firstAiredView = (TextView)view.findViewById(R.id.first_aired);
69 |
70 | int searchResultIndex = getArguments().getInt("searchResultIndex");
71 |
72 | AddShowSearchResults results = AddShowSearchResults.getInstance();
73 | List resultsData = results.getData();
74 |
75 | // Ensure that there is actually data to display, because Android
76 | // may have destroyed it. If there is data display it, if there
77 | // isn't do nothing and the activity will handle the situation.
78 | if (resultsData != null) {
79 | show = resultsData.get(searchResultIndex);
80 |
81 | overviewView.setText(show.getOverview());
82 |
83 | Date firstAired = show.getFirstAired();
84 | if (firstAired != null) {
85 | DateFormat df = DateFormat.getDateInstance();
86 | String text = getString(R.string.first_aired,
87 | df.format(show.getFirstAired()));
88 | firstAiredView.setText(text);
89 | } else {
90 | firstAiredView.setText("");
91 | }
92 | }
93 |
94 | return view;
95 | }
96 |
97 | @Override
98 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
99 | inflater.inflate(R.menu.add_show_preview_fragment, menu);
100 | }
101 |
102 | @Override
103 | public boolean onOptionsItemSelected(MenuItem item) {
104 | switch (item.getItemId()) {
105 | case R.id.menu_add_show:
106 | addShow();
107 | getActivity().finish();
108 |
109 | default:
110 | return super.onOptionsItemSelected(item);
111 | }
112 | }
113 |
114 | private void addShow() {
115 | new AsyncTask().executeAsync(new AddShowTask(show.getId(), show.getName(), show.getLanguage()));
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/AddShowSearchActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.content.Intent;
21 | import android.os.Bundle;
22 | import android.view.MenuItem;
23 | import android.view.Window;
24 |
25 | import androidx.appcompat.app.AppCompatActivity;
26 | import androidx.fragment.app.FragmentTransaction;
27 |
28 | public class AddShowSearchActivity
29 | extends AppCompatActivity
30 | {
31 | @Override
32 | public void onCreate(Bundle savedInstanceState)
33 | {
34 | super.onCreate(savedInstanceState);
35 |
36 | supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
37 | setContentView(R.layout.add_show_search_activity);
38 |
39 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
40 |
41 | Intent intent = getIntent();
42 | String query = intent.getStringExtra("query");
43 |
44 | getSupportActionBar().setTitle(query);
45 |
46 | // create and add search fragment,
47 | // but only on the first time the activity is created
48 | if (savedInstanceState == null) {
49 | AddShowSearchFragment fragment =
50 | AddShowSearchFragment.newInstance(query);
51 | FragmentTransaction transaction =
52 | getSupportFragmentManager().beginTransaction();
53 | transaction.add(R.id.search_fragment_container, fragment);
54 | transaction.commit();
55 | }
56 | }
57 |
58 | @Override
59 | public boolean onOptionsItemSelected(MenuItem item) {
60 | switch (item.getItemId()) {
61 | case android.R.id.home:
62 | Intent intent = new Intent(this, MainActivity.class);
63 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
64 | Intent.FLAG_ACTIVITY_NEW_TASK);
65 | startActivity(intent);
66 |
67 | finish();
68 | return true;
69 |
70 | default:
71 | return super.onOptionsItemSelected(item);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/AddShowSearchResults.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import com.redcoracle.episodes.tvdb.Show;
21 |
22 | import java.util.List;
23 |
24 | public class AddShowSearchResults
25 | {
26 | // singleton instance
27 | private static AddShowSearchResults instance = new AddShowSearchResults();
28 |
29 | private List data;
30 |
31 | private AddShowSearchResults() {
32 | }
33 |
34 | public static AddShowSearchResults getInstance() {
35 | return instance;
36 | }
37 |
38 | public List getData() {
39 | return data;
40 | }
41 |
42 | public void setData(List data) {
43 | this.data = data;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/EpisodesApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.app.Application;
21 | import android.app.NotificationChannel;
22 | import android.app.NotificationManager;
23 | import android.os.Build;
24 | import android.util.Log;
25 |
26 | import com.uwetrottmann.tmdb2.Tmdb;
27 |
28 | public class EpisodesApplication extends Application {
29 | private static final String TAG = EpisodesApplication.class.getName();
30 | private static EpisodesApplication instance;
31 | private Tmdb tmdbClient;
32 |
33 | @Override
34 | public void onCreate() {
35 | super.onCreate();
36 |
37 | instance = this;
38 |
39 | try {
40 | this.tmdbClient = new Tmdb(BuildConfig.TMDB_KEY);
41 | } catch (Exception e) {
42 | Log.d(TAG, "Error initialising TmdbClient", e);
43 | }
44 |
45 | createNotificationChannel();
46 | }
47 |
48 | public static EpisodesApplication getInstance() {
49 | return instance;
50 | }
51 |
52 | public Tmdb getTmdbClient() {
53 | return this.tmdbClient;
54 | }
55 |
56 | private void createNotificationChannel(){
57 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
58 | CharSequence name = getString(R.string.channel_name);
59 | String description = getString(R.string.channel_description);
60 | int importance = NotificationManager.IMPORTANCE_LOW;
61 | NotificationChannel channel = new NotificationChannel("episodes_channel_id", name, importance);
62 | channel.setDescription(description);
63 | NotificationManager notificationManager = getSystemService(NotificationManager.class);
64 | notificationManager.createNotificationChannel(channel);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/EpisodesCounter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.content.SharedPreferences;
21 | import android.database.Cursor;
22 | import android.util.SparseIntArray;
23 |
24 | import com.redcoracle.episodes.db.EpisodesTable;
25 |
26 | import java.util.Collections;
27 | import java.util.Date;
28 | import java.util.Set;
29 | import java.util.TreeSet;
30 |
31 | public class EpisodesCounter
32 | {
33 | private String keyColumn;
34 | private Set keys;
35 | private SparseIntArray numAiredEpisodesMap;
36 | private SparseIntArray numWatchedEpisodesMap;
37 | private SparseIntArray numUpcomingEpisodesMap;
38 |
39 | public EpisodesCounter(String keyColumn) {
40 | this.keyColumn = keyColumn;
41 |
42 | SharedPreferences preferences = Preferences.getSharedPreferences();
43 |
44 | if (preferences.getBoolean("reverse_sort_order", false)) {
45 | keys = new TreeSet(Collections.reverseOrder());
46 | } else {
47 | keys = new TreeSet();
48 | }
49 |
50 | // keys = new TreeSet();
51 | numAiredEpisodesMap = new SparseIntArray();
52 | numWatchedEpisodesMap = new SparseIntArray();
53 | numUpcomingEpisodesMap = new SparseIntArray();
54 | }
55 |
56 | public void swapCursor(Cursor episodesCursor) {
57 | keys.clear();
58 | numAiredEpisodesMap.clear();
59 | numWatchedEpisodesMap.clear();
60 | numUpcomingEpisodesMap.clear();
61 |
62 | if (episodesCursor == null || episodesCursor.moveToFirst() == false) {
63 | return;
64 | }
65 |
66 | do {
67 | final int keyColumnIndex =
68 | episodesCursor.getColumnIndexOrThrow(keyColumn);
69 | final int key = episodesCursor.getInt(keyColumnIndex);
70 |
71 | // check if episode is aired, watched, or upcoming
72 | final int seasonNumberColumnIndex =
73 | episodesCursor.getColumnIndexOrThrow(EpisodesTable.COLUMN_SEASON_NUMBER);
74 | final int seasonNumber =
75 | episodesCursor.getInt(seasonNumberColumnIndex);
76 |
77 | final int firstAiredColumnIndex =
78 | episodesCursor.getColumnIndexOrThrow(EpisodesTable.COLUMN_FIRST_AIRED);
79 | Date firstAired = null;
80 | if (!episodesCursor.isNull(firstAiredColumnIndex)) {
81 | firstAired =
82 | new Date(episodesCursor.getLong(firstAiredColumnIndex)
83 | * 1000);
84 | }
85 |
86 | final int watchedColumnIndex =
87 | episodesCursor.getColumnIndexOrThrow(EpisodesTable.COLUMN_WATCHED);
88 | final boolean watched =
89 | episodesCursor.getInt(watchedColumnIndex) > 0 ? true : false;
90 |
91 |
92 | if (keys.contains(key) == false) {
93 | keys.add(key);
94 | }
95 |
96 | // increment the appropriate counter(s) for this show.
97 | // count shows with no aired date as upcoming,
98 | // unless they're specials in which case count them as aired.
99 | if ((firstAired != null && firstAired.before(new Date()))
100 | || seasonNumber == 0) {
101 | numAiredEpisodesMap.put(key,
102 | numAiredEpisodesMap.get(key) + 1);
103 | if (watched) {
104 | numWatchedEpisodesMap.put(key,
105 | numWatchedEpisodesMap.get(key) + 1);
106 | }
107 | } else {
108 | numUpcomingEpisodesMap.put(key,
109 | numUpcomingEpisodesMap.get(key) + 1);
110 | }
111 | } while (episodesCursor.moveToNext());
112 | }
113 |
114 | public Set getKeys() {
115 | return keys;
116 | }
117 |
118 | public int getNumAiredEpisodes(int key) {
119 | final Integer value = numAiredEpisodesMap.get(key);
120 | if (value == null) {
121 | return 0;
122 | } else {
123 | return value;
124 | }
125 | }
126 |
127 | public int getNumWatchedEpisodes(int key) {
128 | final Integer value = numWatchedEpisodesMap.get(key);
129 | if (value == null) {
130 | return 0;
131 | } else {
132 | return value;
133 | }
134 | }
135 |
136 | public int getNumUpcomingEpisodes(int key) {
137 | final Integer value = numUpcomingEpisodesMap.get(key);
138 | if (value == null) {
139 | return 0;
140 | } else {
141 | return value;
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/FileUtilities.java:
--------------------------------------------------------------------------------
1 | package com.redcoracle.episodes;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.net.Uri;
6 | import android.provider.OpenableColumns;
7 |
8 | import java.io.IOException;
9 | import java.nio.channels.FileChannel;
10 | import java.text.DateFormat;
11 | import java.text.SimpleDateFormat;
12 | import java.util.Date;
13 | import java.util.Locale;
14 |
15 | public class FileUtilities {
16 | public static String get_suggested_filename() {
17 | final Date today = new Date();
18 | final DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HHmm", Locale.getDefault());
19 | return String.format("episodes_%s.db", formatter.format(today));
20 | }
21 |
22 | public static String uri_to_filename(Context context, Uri uri) {
23 | Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
24 | int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
25 | cursor.moveToFirst();
26 | String filename = cursor.getString(nameIndex);
27 | cursor.close();
28 | return filename;
29 | }
30 |
31 | public static void copy_file(FileChannel source, FileChannel destination) {
32 | try {
33 | destination.transferFrom(source, 0, source.size());
34 | source.close();
35 | destination.close();
36 | } catch (IOException e) {
37 | e.printStackTrace();
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/Preferences.java:
--------------------------------------------------------------------------------
1 | package com.redcoracle.episodes;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 |
7 | public class Preferences {
8 | public static SharedPreferences getSharedPreferences() {
9 | Context context = MainActivity.getAppContext();
10 | return PreferenceManager.getDefaultSharedPreferences(context);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/SelectBackupDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.app.Activity;
21 | import android.app.AlertDialog;
22 | import android.app.Dialog;
23 | import android.content.Context;
24 | import android.os.Bundle;
25 |
26 | import androidx.annotation.NonNull;
27 | import androidx.fragment.app.DialogFragment;
28 |
29 | import java.io.File;
30 | import java.util.Arrays;
31 |
32 | public class SelectBackupDialog extends DialogFragment {
33 | public interface OnBackupSelectedListener {
34 | void onBackupSelected(String backupFilename);
35 | }
36 | private OnBackupSelectedListener onBackupSelectedListener;
37 | private Context context;
38 |
39 | @Override
40 | public void onAttach(@NonNull Context context) {
41 | super.onAttach(context);
42 | this.context = context;
43 | Activity activity;
44 | if (context instanceof Activity) {
45 | activity = (Activity) context;
46 | onBackupSelectedListener = (OnBackupSelectedListener) activity;
47 | }
48 | }
49 |
50 | @NonNull
51 | @Override
52 | public Dialog onCreateDialog(Bundle savedInstanceState) {
53 | final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
54 |
55 | final File[] backups = getBackupFiles();
56 |
57 | if (backups != null && backups.length > 0) {
58 | return createDialogBackups(builder, backups);
59 | } else {
60 | return createDialogNoBackups(builder);
61 | }
62 | }
63 |
64 | private File[] getBackupFiles() {
65 | final File[] files = new File(this.context.getExternalFilesDir(null), "episodes").listFiles();
66 |
67 | if (files != null) {
68 | Arrays.sort(files, (lhs, rhs) -> Long.compare(rhs.lastModified(), lhs.lastModified()));
69 | return files;
70 | } else {
71 | return null;
72 | }
73 | }
74 |
75 | private Dialog createDialogBackups(AlertDialog.Builder builder, final File[] backups) {
76 | final String[] names = new String[backups.length];
77 | for (int i = 0; i < backups.length; i++) {
78 | names[i] = backups[i].getName();
79 | }
80 |
81 | builder.setTitle(R.string.restore_dialog_title)
82 | .setItems(names, (dialog, which) -> {
83 | final String path = backups[which].getPath();
84 | onBackupSelectedListener.onBackupSelected(path);
85 | });
86 |
87 | return builder.create();
88 | }
89 |
90 | private Dialog createDialogNoBackups(AlertDialog.Builder builder) {
91 | final File directory = new File(this.context.getExternalFilesDir(null), "episodes");
92 | final String message = getActivity().getString(R.string.restore_dialog_no_backups_message, directory);
93 | builder.setTitle(R.string.restore_dialog_title).setMessage(message);
94 | return builder.create();
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.os.Bundle;
21 |
22 | import androidx.appcompat.app.AppCompatActivity;
23 |
24 | public class SettingsActivity extends AppCompatActivity {
25 | @Override
26 | public void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | setContentView(R.layout.settings_activity);
29 | getSupportFragmentManager()
30 | .beginTransaction()
31 | .replace(R.id.settings_fragment, new SettingsFragment())
32 | .commit();
33 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/SettingsFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.os.Bundle;
21 |
22 | import androidx.preference.PreferenceFragmentCompat;
23 |
24 | public class SettingsFragment extends PreferenceFragmentCompat {
25 | @Override
26 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
27 | setPreferencesFromResource(R.xml.preferences, rootKey);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/ShowDetailsFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.database.Cursor;
21 | import android.net.Uri;
22 | import android.os.Bundle;
23 | import android.view.LayoutInflater;
24 | import android.view.View;
25 | import android.view.ViewGroup;
26 | import android.widget.TextView;
27 |
28 | import androidx.fragment.app.Fragment;
29 | import androidx.loader.app.LoaderManager;
30 | import androidx.loader.content.CursorLoader;
31 | import androidx.loader.content.Loader;
32 |
33 | import com.redcoracle.episodes.db.ShowsProvider;
34 | import com.redcoracle.episodes.db.ShowsTable;
35 |
36 | import java.text.DateFormat;
37 | import java.util.Date;
38 |
39 | public class ShowDetailsFragment
40 | extends Fragment
41 | implements LoaderManager.LoaderCallbacks
42 | {
43 | private int showId;
44 | private TextView overviewView;
45 | private TextView firstAiredView;
46 |
47 | public static ShowDetailsFragment newInstance(int showId) {
48 | ShowDetailsFragment instance = new ShowDetailsFragment();
49 |
50 | Bundle args = new Bundle();
51 | args.putInt("showId", showId);
52 |
53 | instance.setArguments(args);
54 | return instance;
55 | }
56 |
57 | @Override
58 | public void onCreate(Bundle savedInstanceState) {
59 | super.onCreate(savedInstanceState);
60 |
61 | showId = getArguments().getInt("showId");
62 | }
63 |
64 | public View onCreateView(LayoutInflater inflater,
65 | ViewGroup container,
66 | Bundle savedInstanceState) {
67 | View view = inflater.inflate(R.layout.show_details_fragment,
68 | container,
69 | false);
70 |
71 | overviewView = (TextView)view.findViewById(R.id.overview);
72 | firstAiredView = (TextView)view.findViewById(R.id.first_aired);
73 |
74 | return view;
75 | }
76 |
77 | @Override
78 | public void onActivityCreated(Bundle savedInstanceState) {
79 | super.onActivityCreated(savedInstanceState);
80 |
81 | Bundle loaderArgs = new Bundle();
82 | loaderArgs.putInt("showId", showId);
83 | getLoaderManager().initLoader(0, loaderArgs, this);
84 | }
85 |
86 | @Override
87 | public Loader onCreateLoader(int id, Bundle args) {
88 | int showId = args.getInt("showId");
89 | Uri uri = Uri.withAppendedPath(ShowsProvider.CONTENT_URI_SHOWS,
90 | String.valueOf(showId));
91 | String[] projection = {
92 | ShowsTable.COLUMN_OVERVIEW,
93 | ShowsTable.COLUMN_FIRST_AIRED
94 | };
95 | return new CursorLoader(getActivity(),
96 | uri,
97 | projection,
98 | null,
99 | null,
100 | null);
101 | }
102 |
103 | @Override
104 | public void onLoadFinished(Loader loader, Cursor data) {
105 | if (data != null && data.moveToFirst()) {
106 |
107 | int overviewColumnIndex =
108 | data.getColumnIndexOrThrow(ShowsTable.COLUMN_OVERVIEW);
109 | if (data.isNull(overviewColumnIndex)) {
110 | overviewView.setVisibility(View.GONE);
111 | } else {
112 | overviewView.setText(data.getString(overviewColumnIndex).trim());
113 | overviewView.setVisibility(View.VISIBLE);
114 | }
115 |
116 | int firstAiredColumnIndex =
117 | data.getColumnIndexOrThrow(ShowsTable.COLUMN_FIRST_AIRED);
118 | if (data.isNull(firstAiredColumnIndex)) {
119 | firstAiredView.setVisibility(View.GONE);
120 | } else {
121 | Date firstAired =
122 | new Date(data.getLong(firstAiredColumnIndex) * 1000);
123 | DateFormat df = DateFormat.getDateInstance();
124 | String firstAiredText = getString(R.string.first_aired,
125 | df.format(firstAired));
126 | firstAiredView.setText(firstAiredText);
127 | firstAiredView.setVisibility(View.VISIBLE);
128 | }
129 |
130 | } else {
131 | overviewView.setVisibility(View.GONE);
132 | firstAiredView.setVisibility(View.GONE);
133 | }
134 | }
135 |
136 | @Override
137 | public void onLoaderReset(Loader loader) {
138 | onLoadFinished(loader, null);
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/ShowNotesFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Daniele Ricci
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes;
19 |
20 | import android.database.Cursor;
21 | import android.net.Uri;
22 | import android.os.Bundle;
23 | import android.view.LayoutInflater;
24 | import android.view.View;
25 | import android.view.ViewGroup;
26 | import android.widget.TextView;
27 |
28 | import androidx.fragment.app.Fragment;
29 | import androidx.loader.app.LoaderManager;
30 | import androidx.loader.content.CursorLoader;
31 | import androidx.loader.content.Loader;
32 |
33 | import com.redcoracle.episodes.db.ShowsProvider;
34 | import com.redcoracle.episodes.db.ShowsTable;
35 |
36 | public class ShowNotesFragment
37 | extends Fragment
38 | implements LoaderManager.LoaderCallbacks
39 | {
40 | private int showId;
41 | private TextView notesView;
42 |
43 | public static ShowNotesFragment newInstance(int showId) {
44 | ShowNotesFragment instance = new ShowNotesFragment();
45 |
46 | Bundle args = new Bundle();
47 | args.putInt("showId", showId);
48 |
49 | instance.setArguments(args);
50 | return instance;
51 | }
52 |
53 | @Override
54 | public void onCreate(Bundle savedInstanceState) {
55 | super.onCreate(savedInstanceState);
56 |
57 | showId = getArguments().getInt("showId");
58 | }
59 |
60 | public View onCreateView(LayoutInflater inflater,
61 | ViewGroup container,
62 | Bundle savedInstanceState) {
63 | final View view = inflater.inflate(R.layout.show_notes_fragment,
64 | container,
65 | false);
66 |
67 | notesView = (TextView)view.findViewById(R.id.notes);
68 |
69 | return view;
70 | }
71 |
72 | @Override
73 | public void onActivityCreated(Bundle savedInstanceState) {
74 | super.onActivityCreated(savedInstanceState);
75 |
76 | final Bundle loaderArgs = new Bundle();
77 | loaderArgs.putInt("showId", showId);
78 | getLoaderManager().initLoader(0, loaderArgs, this);
79 | }
80 |
81 | @Override
82 | public Loader onCreateLoader(int id, Bundle args) {
83 | final int showId = args.getInt("showId");
84 | final Uri uri = Uri.withAppendedPath(ShowsProvider.CONTENT_URI_SHOWS,
85 | String.valueOf(showId));
86 | final String[] projection = {
87 | ShowsTable.COLUMN_NOTES
88 | };
89 | return new CursorLoader(getActivity(),
90 | uri,
91 | projection,
92 | null,
93 | null,
94 | null);
95 | }
96 |
97 | @Override
98 | public void onLoadFinished(Loader loader, Cursor data) {
99 | if (data != null && data.moveToFirst()) {
100 |
101 | final int notesColumnIndex =
102 | data.getColumnIndexOrThrow(ShowsTable.COLUMN_NOTES);
103 | if (data.isNull(notesColumnIndex)) {
104 | notesView.setText("");
105 | } else {
106 | final String text = data.getString(notesColumnIndex);
107 | notesView.setText(text);
108 | }
109 | }
110 | }
111 |
112 | @Override
113 | public void onLoaderReset(Loader loader) {
114 | onLoadFinished(loader, null);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/db/DatabaseOpenHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.db;
19 |
20 | import android.content.Context;
21 | import android.database.sqlite.SQLiteDatabase;
22 | import android.database.sqlite.SQLiteOpenHelper;
23 | import android.util.Log;
24 |
25 | public class DatabaseOpenHelper extends SQLiteOpenHelper {
26 | private static final String TAG = "DatabaseOpenHelper";
27 | private static final String name = "episodes.db";
28 | private static final int version = 9;
29 |
30 | DatabaseOpenHelper(Context context) {
31 | super(context, name, null, version);
32 | }
33 |
34 | @Override
35 | public void onCreate(SQLiteDatabase db) {
36 | Log.d(TAG, "creating database");
37 | ShowsTable.onCreate(db);
38 | EpisodesTable.onCreate(db);
39 | }
40 |
41 | @Override
42 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
43 | Log.d(TAG, String.format("upgrading database from version %d to %d", oldVersion, newVersion));
44 | ShowsTable.onUpgrade(db, oldVersion, newVersion);
45 | EpisodesTable.onUpgrade(db, oldVersion, newVersion);
46 | }
47 |
48 | @Override
49 | public void onOpen(SQLiteDatabase db) {
50 | Log.d(TAG, "opening database.");
51 | }
52 |
53 | public static String getDbName() {
54 | return name;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/db/EpisodesTable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.db;
19 |
20 | import android.database.Cursor;
21 | import android.database.sqlite.SQLiteDatabase;
22 | import android.provider.BaseColumns;
23 | import android.util.Log;
24 |
25 | import java.util.Arrays;
26 |
27 | public class EpisodesTable {
28 | private static final String TAG = "EpisodesTable";
29 |
30 | static final String TABLE_NAME = "episodes";
31 |
32 | public static final String COLUMN_ID = BaseColumns._ID;
33 | public static final String COLUMN_TVDB_ID = "tvdb_id";
34 | public static final String COLUMN_TMDB_ID = "tmdb_id";
35 | public static final String COLUMN_IMDB_ID = "imdb_id";
36 | public static final String COLUMN_SHOW_ID = "show_id";
37 | public static final String COLUMN_NAME = "name";
38 | public static final String COLUMN_LANGUAGE = "language";
39 | public static final String COLUMN_OVERVIEW = "overview";
40 | public static final String COLUMN_EPISODE_NUMBER = "episode_number";
41 | public static final String COLUMN_SEASON_NUMBER = "season_number";
42 | public static final String COLUMN_FIRST_AIRED = "first_aired";
43 | public static final String COLUMN_WATCHED = "watched";
44 |
45 | public static String createTableSQL(String table_name) {
46 | return String.format(
47 | "CREATE TABLE %s (" +
48 | "%s INTEGER PRIMARY KEY," +
49 | "%s INTEGER UNIQUE," +
50 | "%s INTEGER UNIQUE," +
51 | "%s TEXT UNIQUE," +
52 | "%s INTEGER NOT NULL," +
53 | "%s VARCHAR(200) NOT NULL," +
54 | "%s TEXT," +
55 | "%s TEXT," +
56 | "%s INTEGER," +
57 | "%s INTEGER," +
58 | "%s DATE," +
59 | "%s BOOLEAN" +
60 | ");",
61 | table_name,
62 | COLUMN_ID,
63 | COLUMN_TVDB_ID,
64 | COLUMN_TMDB_ID,
65 | COLUMN_IMDB_ID,
66 | COLUMN_SHOW_ID,
67 | COLUMN_NAME,
68 | COLUMN_LANGUAGE,
69 | COLUMN_OVERVIEW,
70 | COLUMN_EPISODE_NUMBER,
71 | COLUMN_SEASON_NUMBER,
72 | COLUMN_FIRST_AIRED,
73 | COLUMN_WATCHED
74 | );
75 | }
76 |
77 | public static void onCreate(SQLiteDatabase db) {
78 | String create = createTableSQL(TABLE_NAME);
79 |
80 | Log.d(TAG, String.format("creating episodes table: %s", create));
81 |
82 | db.execSQL(create);
83 | }
84 |
85 | static void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
86 | if (oldVersion <= 7) {
87 | // Add language column
88 | Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, null);
89 | String[] columns = cursor.getColumnNames();
90 | if (!Arrays.asList(columns).contains(COLUMN_LANGUAGE)) {
91 | Log.d(TAG, "upgrading episodes table: adding language column");
92 | db.execSQL(String.format("ALTER TABLE %s ADD COLUMN %s TEXT", TABLE_NAME, COLUMN_LANGUAGE));
93 | }
94 | cursor.close();
95 | }
96 |
97 | if (oldVersion <= 8) {
98 | // Add TMDB/IMDB columns
99 | db.beginTransaction();
100 | try {
101 | final String temp_table_name = String.format("new_%s", TABLE_NAME);
102 | String create_table = createTableSQL(temp_table_name);
103 | String insert_columns = String.format(
104 | "%s, %s, %s, %s, %s, %s, %s, %s, %s, %s",
105 | COLUMN_ID, COLUMN_TVDB_ID, COLUMN_SHOW_ID, COLUMN_NAME, COLUMN_LANGUAGE,
106 | COLUMN_OVERVIEW, COLUMN_EPISODE_NUMBER, COLUMN_SEASON_NUMBER,
107 | COLUMN_FIRST_AIRED, COLUMN_WATCHED
108 | );
109 | db.execSQL(create_table);
110 | db.execSQL(String.format(
111 | "INSERT INTO %s (%s) SELECT %s FROM %s",
112 | temp_table_name, insert_columns, insert_columns, TABLE_NAME
113 | ));
114 | db.execSQL(String.format("DROP TABLE %s", TABLE_NAME));
115 | db.execSQL(String.format(
116 | "ALTER TABLE %s RENAME TO %s",
117 | temp_table_name, TABLE_NAME
118 | ));
119 | db.setTransactionSuccessful();
120 | } finally {
121 | db.endTransaction();
122 | }
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/services/AddShowTask.java:
--------------------------------------------------------------------------------
1 | package com.redcoracle.episodes.services;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.ContentValues;
5 | import android.content.Context;
6 | import android.database.Cursor;
7 | import android.net.Uri;
8 | import android.os.Handler;
9 | import android.os.Looper;
10 | import android.util.Log;
11 | import android.widget.Toast;
12 |
13 | import com.redcoracle.episodes.EpisodesApplication;
14 | import com.redcoracle.episodes.R;
15 | import com.redcoracle.episodes.db.EpisodesTable;
16 | import com.redcoracle.episodes.db.ShowsProvider;
17 | import com.redcoracle.episodes.db.ShowsTable;
18 | import com.redcoracle.episodes.tvdb.Client;
19 | import com.redcoracle.episodes.tvdb.Episode;
20 | import com.redcoracle.episodes.tvdb.Show;
21 |
22 | import java.util.LinkedList;
23 | import java.util.concurrent.Callable;
24 |
25 | public class AddShowTask implements Callable {
26 | private static final String TAG = "AddShowTask";
27 | private final int tmdbId;
28 | private final String showName;
29 | private final String showLanguage;
30 | private final Context context;
31 |
32 | public AddShowTask(int tmdbId, String showName, String showLanguage) {
33 | this.tmdbId = tmdbId;
34 | this.showName = showName;
35 | this.showLanguage = showLanguage;
36 | this.context = EpisodesApplication.getInstance().getApplicationContext();
37 | }
38 |
39 | @Override
40 | public Void call() {
41 | final Client tmdbClient = new Client();
42 | Show show = tmdbClient.getShow(this.tmdbId, this.showLanguage, false);
43 |
44 | if (!checkAlreadyAdded(show)) {
45 | this.showMessage(this.context.getString(R.string.adding_show, showName));
46 | show = tmdbClient.getShow(this.tmdbId, this.showLanguage, true);
47 | final int showId = insertShow(show);
48 | this.insertEpisodes(show.getEpisodes().toArray(new Episode[0]), showId);
49 | showMessage(this.context.getString(R.string.show_added, showName));
50 | } else {
51 | showMessage(this.context.getString(R.string.show_already_added, showName));
52 | }
53 | return null;
54 | }
55 |
56 | private boolean checkAlreadyAdded(Show show) {
57 | final String[] projection = {};
58 | String selection = String.format("%s=?", ShowsTable.COLUMN_TMDB_ID);
59 | LinkedList selectionArgs = new LinkedList<>();
60 | selectionArgs.add(Integer.valueOf(show.getTmdbId()).toString());
61 |
62 | if (show.getTvdbId() > 0) {
63 | selection += String.format(" OR %s=?", ShowsTable.COLUMN_TVDB_ID);
64 | selectionArgs.add(Integer.valueOf(show.getTvdbId()).toString());
65 | }
66 | if (show.getImdbId() != null && !show.getImdbId().equals("")) {
67 | selection += String.format(" OR %s=?", ShowsTable.COLUMN_IMDB_ID);
68 | selectionArgs.add(show.getImdbId());
69 | }
70 | final ContentResolver resolver = this.context.getContentResolver();
71 | final Cursor cursor = resolver.query(
72 | ShowsProvider.CONTENT_URI_SHOWS,
73 | projection,
74 | selection,
75 | selectionArgs.toArray(new String[0]),
76 | null
77 | );
78 | final boolean existing = cursor.moveToFirst();
79 | cursor.close();
80 | return existing;
81 | }
82 |
83 | private int insertShow(Show show){
84 | final ContentValues showValues = new ContentValues();
85 | if (show.getTvdbId() != 0) {
86 | showValues.put(ShowsTable.COLUMN_TVDB_ID, show.getTvdbId());
87 | }
88 | showValues.put(ShowsTable.COLUMN_TMDB_ID, show.getTmdbId());
89 | showValues.put(ShowsTable.COLUMN_IMDB_ID, show.getImdbId());
90 | showValues.put(ShowsTable.COLUMN_NAME, show.getName());
91 | showValues.put(ShowsTable.COLUMN_LANGUAGE, show.getLanguage());
92 | showValues.put(ShowsTable.COLUMN_OVERVIEW, show.getOverview());
93 | if (show.getFirstAired() != null) {
94 | showValues.put(ShowsTable.COLUMN_FIRST_AIRED, show.getFirstAired().getTime() / 1000);
95 | }
96 | showValues.put(ShowsTable.COLUMN_BANNER_PATH, show.getBannerPath());
97 | showValues.put(ShowsTable.COLUMN_FANART_PATH, show.getFanartPath());
98 | showValues.put(ShowsTable.COLUMN_POSTER_PATH, show.getPosterPath());
99 |
100 | final Uri showUri = this.context.getContentResolver().insert(ShowsProvider.CONTENT_URI_SHOWS, showValues);
101 | final int showId = Integer.parseInt(showUri.getLastPathSegment());
102 | Log.i(TAG, String.format("show %s successfully added to database as row %d. adding episodes", show.getName(), showId));
103 | return showId;
104 | }
105 |
106 | private void insertEpisodes(Episode[] episodes, int showId) {
107 | final ContentValues[] values = new ContentValues[episodes.length];
108 |
109 | for (int i = 0; i < episodes.length; i++) {
110 | ContentValues value = new ContentValues();
111 | value.put(EpisodesTable.COLUMN_TVDB_ID, episodes[i].getTvdbId());
112 | value.put(EpisodesTable.COLUMN_TMDB_ID, episodes[i].getTmdbId());
113 | value.put(EpisodesTable.COLUMN_IMDB_ID, episodes[i].getImdbId());
114 | value.put(EpisodesTable.COLUMN_SHOW_ID, showId);
115 | value.put(EpisodesTable.COLUMN_NAME, episodes[i].getName());
116 | value.put(EpisodesTable.COLUMN_LANGUAGE, episodes[i].getLanguage());
117 | value.put(EpisodesTable.COLUMN_OVERVIEW, episodes[i].getOverview());
118 | value.put(EpisodesTable.COLUMN_EPISODE_NUMBER, episodes[i].getEpisodeNumber());
119 | value.put(EpisodesTable.COLUMN_SEASON_NUMBER, episodes[i].getSeasonNumber());
120 | if (episodes[i].getFirstAired() != null) {
121 | value.put(EpisodesTable.COLUMN_FIRST_AIRED, episodes[i].getFirstAired().getTime() / 1000);
122 | }
123 | values[i] = value;
124 | }
125 |
126 | for (ContentValues value : values) {
127 | this.context.getContentResolver().insert(ShowsProvider.CONTENT_URI_EPISODES, value);
128 | }
129 | }
130 |
131 | private void showMessage(String message) {
132 | Handler handler = new Handler(Looper.getMainLooper());
133 | handler.post(() -> Toast.makeText(context, message, Toast.LENGTH_SHORT).show());
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/services/AsyncTask.java:
--------------------------------------------------------------------------------
1 | package com.redcoracle.episodes.services;
2 |
3 | import java.util.concurrent.Callable;
4 | import java.util.concurrent.Executor;
5 | import java.util.concurrent.Executors;
6 |
7 | public class AsyncTask {
8 | private final Executor executor = Executors.newSingleThreadExecutor();
9 |
10 | public void executeAsync(Callable callable) {
11 | executor.execute(() -> {
12 | try {
13 | callable.call();
14 | } catch (Exception e) {
15 | e.printStackTrace();
16 | }
17 | });
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/services/BackupTask.java:
--------------------------------------------------------------------------------
1 | package com.redcoracle.episodes.services;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 | import android.util.Log;
6 | import android.widget.Toast;
7 |
8 | import androidx.core.content.ContextCompat;
9 |
10 | import com.redcoracle.episodes.EpisodesApplication;
11 | import com.redcoracle.episodes.R;
12 | import com.redcoracle.episodes.db.DatabaseOpenHelper;
13 |
14 | import java.io.File;
15 | import java.io.FileInputStream;
16 | import java.io.FileNotFoundException;
17 | import java.io.FileOutputStream;
18 | import java.io.IOException;
19 | import java.nio.channels.FileChannel;
20 | import java.util.concurrent.Callable;
21 |
22 | public class BackupTask implements Callable {
23 | private final static String TAG = BackupTask.class.getName();
24 | private final Context context;
25 | private final String destinationFileName;
26 |
27 | public BackupTask(String destinationFileName) {
28 | this.destinationFileName = destinationFileName;
29 | this.context = EpisodesApplication.getInstance().getApplicationContext();
30 | }
31 |
32 | public Void call() {
33 | Log.i(TAG, "Backing up library.");
34 | if (!isExternalStorageReadable()) {
35 | Log.i(TAG, "Storage is not readable.");
36 | return null;
37 | }
38 | final File databaseFile = this.context.getDatabasePath(DatabaseOpenHelper.getDbName());
39 | final File destinationDirectory = new File(this.context.getExternalFilesDir(null), "episodes");
40 | if (!destinationDirectory.mkdirs()) {
41 | Log.e(TAG, String.format("Error creating backup directory '%s'.", destinationDirectory.getPath()));
42 | }
43 | final File destinationFile = new File(destinationDirectory, this.destinationFileName);
44 | try {
45 | FileChannel src = new FileInputStream(databaseFile).getChannel();
46 | FileChannel dest = new FileOutputStream(destinationFile).getChannel();
47 | dest.transferFrom(src, 0, src.size());
48 | ContextCompat.getMainExecutor(this.context).execute(() -> Toast.makeText(
49 | this.context,
50 | String.format(this.context.getString(R.string.back_up_success_message), this.destinationFileName),
51 | Toast.LENGTH_LONG
52 | ).show());
53 | Log.i(TAG, String.format("Library backed up successfully: '%s'.", destinationFile.getPath()));
54 | src.close();
55 | dest.close();
56 | } catch (FileNotFoundException e) {
57 | e.printStackTrace();
58 | } catch (IOException e) {
59 | e.printStackTrace();
60 | }
61 | return null;
62 | }
63 |
64 | private boolean isExternalStorageReadable() {
65 | String state = Environment.getExternalStorageState();
66 | return Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/services/DeleteShowTask.java:
--------------------------------------------------------------------------------
1 | package com.redcoracle.episodes.services;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.Context;
5 | import android.net.Uri;
6 | import android.util.Log;
7 |
8 | import com.redcoracle.episodes.EpisodesApplication;
9 | import com.redcoracle.episodes.db.EpisodesTable;
10 | import com.redcoracle.episodes.db.ShowsProvider;
11 |
12 | import java.util.concurrent.Callable;
13 |
14 | public class DeleteShowTask implements Callable {
15 | private static final String TAG = DeleteShowTask.class.getName();
16 | private int showId;
17 | private Context context;
18 |
19 | public DeleteShowTask(int showId) {
20 | this.showId = showId;
21 | this.context = EpisodesApplication.getInstance().getApplicationContext();
22 | }
23 |
24 | @Override
25 | public Void call() {
26 | final ContentResolver resolver = this.context.getContentResolver();
27 | final String selection = String.format("%s=?", EpisodesTable.COLUMN_SHOW_ID);
28 | final String[] selectionArgs = {String.valueOf(this.showId)};
29 | int episodes = resolver.delete(ShowsProvider.CONTENT_URI_EPISODES, selection, selectionArgs);
30 | Log.d(TAG, String.format("Deleted %s episodes", episodes));
31 | resolver.delete(Uri.withAppendedPath(ShowsProvider.CONTENT_URI_SHOWS, String.valueOf(showId)), null, null);
32 | return null;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/services/RefreshAllShowsTask.java:
--------------------------------------------------------------------------------
1 | package com.redcoracle.episodes.services;
2 |
3 | import android.content.ContentResolver;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.net.Uri;
7 |
8 | import androidx.core.app.NotificationCompat;
9 | import androidx.core.app.NotificationManagerCompat;
10 |
11 | import com.redcoracle.episodes.EpisodesApplication;
12 | import com.redcoracle.episodes.R;
13 | import com.redcoracle.episodes.db.ShowsProvider;
14 | import com.redcoracle.episodes.db.ShowsTable;
15 |
16 | import java.util.concurrent.Callable;
17 |
18 | import static com.redcoracle.episodes.RefreshShowUtil.refreshShow;
19 |
20 | public class RefreshAllShowsTask implements Callable {
21 | @Override
22 | public Void call() {
23 | Context context = EpisodesApplication.getInstance().getApplicationContext();
24 | ContentResolver resolver = context.getContentResolver();
25 | final Uri showUri = ShowsProvider.CONTENT_URI_SHOWS;
26 | final String[] projection = {
27 | ShowsTable.COLUMN_ID,
28 | ShowsTable.COLUMN_NAME
29 | };
30 | final String sort = ShowsTable.COLUMN_NAME + " ASC";
31 | final Cursor cursor = resolver.query(showUri, projection, null, null, sort);
32 | final int idColumnIndex = cursor.getColumnIndex(ShowsTable.COLUMN_ID);
33 | final int nameColumnIndex = cursor.getColumnIndex(ShowsTable.COLUMN_NAME);
34 | final int total = cursor.getCount();
35 |
36 | NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
37 | NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, "episodes_channel_id");
38 | notificationBuilder
39 | .setContentTitle("Refreshing Shows")
40 | .setSmallIcon(R.drawable.ic_show_starred)
41 | .setPriority(NotificationCompat.PRIORITY_DEFAULT);
42 | int current = 0;
43 | notificationBuilder.setProgress(total, current, false);
44 | notificationManager.notify(0, notificationBuilder.build());
45 |
46 | int showId;
47 | String showName;
48 | cursor.moveToFirst();
49 | do {
50 | showId = cursor.getInt(idColumnIndex);
51 | showName = cursor.getString(nameColumnIndex);
52 | notificationBuilder.setContentText(showName);
53 | notificationBuilder.setProgress(total, current, false);
54 | notificationManager.notify(0, notificationBuilder.build());
55 | refreshShow(showId, resolver);
56 | current += 1;
57 | } while (cursor.moveToNext());
58 | cursor.close();
59 | notificationBuilder.setContentText("Refresh complete!").setProgress(0, 0, false);
60 | notificationManager.notify(0, notificationBuilder.build());
61 | return null;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/services/RefreshShowService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013-2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.services;
19 |
20 | import android.app.IntentService;
21 | import android.content.Intent;
22 |
23 | import com.redcoracle.episodes.RefreshShowUtil;
24 |
25 | public class RefreshShowService extends IntentService
26 | {
27 | public RefreshShowService() {
28 | super(RefreshShowService.class.getName());
29 | }
30 |
31 | @Override
32 | protected void onHandleIntent(Intent intent) {
33 | final int showId = intent.getIntExtra("showId", 0);
34 |
35 | RefreshShowUtil.refreshShow(showId, getContentResolver());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/services/RefreshShowTask.java:
--------------------------------------------------------------------------------
1 | package com.redcoracle.episodes.services;
2 |
3 | import android.content.Context;
4 |
5 | import com.redcoracle.episodes.EpisodesApplication;
6 | import com.redcoracle.episodes.RefreshShowUtil;
7 |
8 | import java.util.concurrent.Callable;
9 |
10 | public class RefreshShowTask implements Callable {
11 | private static final String TAG = DeleteShowTask.class.getName();
12 | private int showId;
13 | private Context context;
14 |
15 | public RefreshShowTask(int showId) {
16 | this.showId = showId;
17 | this.context = EpisodesApplication.getInstance().getApplicationContext();
18 | }
19 |
20 | @Override
21 | public Void call() {
22 | RefreshShowUtil.refreshShow(showId, this.context.getContentResolver());
23 | return null;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/services/RestoreTask.java:
--------------------------------------------------------------------------------
1 | package com.redcoracle.episodes.services;
2 |
3 | import android.content.Context;
4 | import android.os.Environment;
5 | import android.util.Log;
6 | import android.widget.Toast;
7 |
8 | import androidx.core.content.ContextCompat;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.redcoracle.episodes.EpisodesApplication;
12 | import com.redcoracle.episodes.R;
13 | import com.redcoracle.episodes.db.DatabaseOpenHelper;
14 | import com.redcoracle.episodes.db.ShowsProvider;
15 |
16 | import java.io.File;
17 | import java.io.FileInputStream;
18 | import java.io.FileOutputStream;
19 | import java.io.IOException;
20 | import java.nio.channels.FileChannel;
21 | import java.util.concurrent.Callable;
22 |
23 | public class RestoreTask implements Callable {
24 | private final static String TAG = RestoreTask.class.getName();
25 | private final Context context;
26 | private final String filename;
27 |
28 |
29 | public RestoreTask(String filename) {
30 | this.context = EpisodesApplication.getInstance().getApplicationContext();
31 | this.filename = filename;
32 | }
33 |
34 | public Void call() {
35 | if (!isExternalStorageWritable()) {
36 | return null;
37 | }
38 | final File backupFile = new File(this.filename);
39 | final File databaseFile = this.context.getDatabasePath(DatabaseOpenHelper.getDbName());
40 | try {
41 | FileChannel src = new FileInputStream(backupFile).getChannel();
42 | FileChannel dest = new FileOutputStream(databaseFile).getChannel();
43 | dest.transferFrom(src, 0, src.size());
44 | Glide.get(this.context).clearDiskCache();
45 | ContextCompat.getMainExecutor(this.context).execute(() -> Toast.makeText(
46 | this.context,
47 | this.context.getString(R.string.restore_success_message),
48 | Toast.LENGTH_LONG
49 | ).show());
50 | Log.i(TAG, "Library restored successfully.");
51 | } catch (IOException e) {
52 | Log.e(TAG, String.format("Error restoring library: %s", e.toString()));
53 | } finally {
54 | ShowsProvider.reloadDatabase(this.context);
55 | }
56 | return null;
57 | }
58 |
59 | private boolean isExternalStorageWritable() {
60 | String state = Environment.getExternalStorageState();
61 | return Environment.MEDIA_MOUNTED.equals(state);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/tvdb/Episode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.tvdb;
19 |
20 | import java.util.Date;
21 |
22 | public class Episode {
23 | private int id;
24 | private Integer tvdbId;
25 | private Integer tmdbId;
26 | private String imdbId;
27 | private String name;
28 | private String language;
29 | private String overview;
30 | private int episodeNumber;
31 | private int seasonNumber;
32 | private Date firstAired;
33 |
34 | Episode() {
35 | }
36 |
37 | public String identifier() {
38 | return String.format("%s-%s", this.seasonNumber, this.episodeNumber);
39 | }
40 |
41 | public int getId() {
42 | return id;
43 | }
44 |
45 | public void setId(int id) {
46 | this.id = id;
47 | }
48 |
49 | public Integer getTvdbId() {
50 | return this.tvdbId;
51 | }
52 |
53 | public void setTvdbId(Integer id) {
54 | this.tvdbId = id;
55 | }
56 |
57 | public int getTmdbId() {
58 | return this.tmdbId;
59 | }
60 |
61 | public void setTmdbId(int id) {
62 | this.tmdbId = id;
63 | }
64 |
65 | public String getImdbId() {
66 | return this.imdbId;
67 | }
68 |
69 | public void setImdbId(String id) {
70 | this.imdbId = id;
71 | }
72 |
73 | public String getName() {
74 | return name;
75 | }
76 |
77 | public void setName(String name) {
78 | this.name = name;
79 | }
80 |
81 | public String getLanguage() {
82 | return language;
83 | }
84 |
85 | public void setLanguage(String language) {
86 | this.language = language;
87 | }
88 |
89 | public String getOverview() {
90 | return overview;
91 | }
92 |
93 | public void setOverview(String overview) {
94 | this.overview = overview;
95 | }
96 |
97 | public int getEpisodeNumber() {
98 | return episodeNumber;
99 | }
100 |
101 | void setEpisodeNumber(int episodeNumber) {
102 | this.episodeNumber = episodeNumber;
103 | }
104 |
105 | public int getSeasonNumber() {
106 | return seasonNumber;
107 | }
108 |
109 | void setSeasonNumber(int seasonNumber) {
110 | this.seasonNumber = seasonNumber;
111 | }
112 |
113 | public Date getFirstAired() {
114 | return firstAired;
115 | }
116 |
117 | void setFirstAired(Date firstAired) {
118 | this.firstAired = firstAired;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/tvdb/GetEpisodesParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.tvdb;
19 |
20 | import android.util.Log;
21 |
22 | import com.uwetrottmann.tmdb2.entities.TvEpisode;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | class GetEpisodesParser {
28 | private static final String TAG = GetEpisodesParser.class.getName();
29 |
30 | ArrayList parse(List tmdbEpisodes) {
31 | try {
32 | ArrayList episodes = new ArrayList<>(tmdbEpisodes.size());
33 | for (TvEpisode episode : tmdbEpisodes) {
34 | Episode e = new Episode();
35 | e.setId(episode.id);
36 | e.setTmdbId(episode.id);
37 | if (episode.external_ids != null) {
38 | if (episode.external_ids.tvdb_id != null) {
39 | e.setTvdbId(episode.external_ids.tvdb_id);
40 | }
41 | if (episode.external_ids.imdb_id != null) {
42 | e.setImdbId(episode.external_ids.imdb_id);
43 | }
44 | }
45 | e.setName(episode.name != null ? episode.name : "");
46 | e.setOverview(episode.overview);
47 | e.setSeasonNumber(episode.season_number);
48 | e.setEpisodeNumber(episode.episode_number);
49 | e.setFirstAired(episode.air_date);
50 | episodes.add(e);
51 | }
52 | return episodes;
53 | } catch (Exception ex) {
54 | Log.w(TAG, ex);
55 | return null;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/tvdb/GetShowParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.tvdb;
19 |
20 | import android.util.Log;
21 |
22 | import com.uwetrottmann.tmdb2.entities.TvShow;
23 |
24 | class GetShowParser {
25 | private static final String TAG = "GetShowParser";
26 |
27 | Show parse(TvShow series, String language) {
28 | Show show;
29 | try {
30 | show = new Show();
31 | if (series.id != null) {
32 | show.setId(series.id);
33 | show.setTmdbId(series.id);
34 | } else {
35 | Log.w(TAG, String.format("Show does not have an ID: %s", series.name));
36 | return null;
37 | }
38 | if (series.external_ids != null) {
39 | if (series.external_ids.tvdb_id != null) {
40 | show.setTvdbId(series.external_ids.tvdb_id);
41 | }
42 | if (series.external_ids.imdb_id != null) {
43 | show.setImdbId(series.external_ids.imdb_id);
44 | }
45 | }
46 | show.setName(series.name);
47 | show.setLanguage(language);
48 | show.setOverview(series.overview);
49 | show.setFirstAired(series.first_air_date);
50 | show.setBannerPath(series.backdrop_path);
51 | show.setPosterPath(series.poster_path);
52 | } catch (Exception e) {
53 | Log.w(TAG, e);
54 | return null;
55 | }
56 | return show;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/tvdb/SearchShowsParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.tvdb;
19 |
20 | import android.util.Log;
21 |
22 | import com.uwetrottmann.tmdb2.entities.BaseTvShow;
23 | import com.uwetrottmann.tmdb2.entities.TvShowResultsPage;
24 |
25 | import java.util.LinkedList;
26 | import java.util.List;
27 |
28 | class SearchShowsParser {
29 | private static final String TAG = SearchShowsParser.class.getName();
30 |
31 | private List parsed;
32 |
33 | List parse(TvShowResultsPage results, String language) {
34 | try {
35 | List series = results.results;
36 | parsed = new LinkedList<>();
37 | for(BaseTvShow s : series) {
38 | Show show = new Show();
39 | show.setId(s.id);
40 | show.setTmdbId(s.id);
41 | show.setName(s.name);
42 | show.setLanguage(language);
43 | show.setOverview(s.overview);
44 | show.setFirstAired(s.first_air_date);
45 | parsed.add(show);
46 | }
47 | } catch (Exception e) {
48 | Log.w(TAG, e);
49 | }
50 | return parsed;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/tvdb/Show.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012-2014 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.tvdb;
19 |
20 | import java.util.Date;
21 | import java.util.List;
22 |
23 | public class Show {
24 | private int id;
25 | private int tvdbId;
26 | private int tmdbId;
27 | private String imdbId;
28 | private String name;
29 | private String language;
30 | private String overview;
31 | private Date firstAired;
32 | private String bannerPath;
33 | private String fanartPath;
34 | private String posterPath;
35 | private List episodes;
36 |
37 | public Show() {
38 | name = "";
39 | language = "";
40 | overview = "";
41 | firstAired = null;
42 | bannerPath = "";
43 | fanartPath = "";
44 | posterPath = "";
45 | episodes = null;
46 | }
47 |
48 | public int getId() {
49 | return id;
50 | }
51 |
52 | public void setId(int id) {
53 | this.id = id;
54 | }
55 |
56 | public int getTvdbId() {
57 | return tvdbId;
58 | }
59 |
60 | public void setTvdbId(int tvdbId) {
61 | this.tvdbId = tvdbId;
62 | }
63 |
64 | public int getTmdbId() {
65 | return this.tmdbId;
66 | }
67 |
68 | public void setTmdbId(int tmdbId) {
69 | this.tmdbId = tmdbId;
70 | }
71 |
72 | public String getImdbId() {
73 | return this.imdbId;
74 | }
75 |
76 | public void setImdbId(String imdbId) {
77 | this.imdbId = imdbId;
78 | }
79 |
80 | public String getName() {
81 | return name;
82 | }
83 |
84 | public void setName(String name) {
85 | this.name = name;
86 | }
87 |
88 | public String getLanguage() {
89 | return language;
90 | }
91 |
92 | void setLanguage(String language) {
93 | this.language = language;
94 | }
95 |
96 | public String getOverview() {
97 | return overview;
98 | }
99 |
100 | public void setOverview(String overview) {
101 | this.overview = overview;
102 | }
103 |
104 | public Date getFirstAired() {
105 | return firstAired;
106 | }
107 |
108 | void setFirstAired(Date firstAired) {
109 | this.firstAired = firstAired;
110 | }
111 |
112 | public String getBannerPath() {
113 | return bannerPath;
114 | }
115 |
116 | void setBannerPath(String bannerPath) {
117 | this.bannerPath = bannerPath;
118 | }
119 |
120 | public String getFanartPath() {
121 | return fanartPath;
122 | }
123 |
124 | void setFanartPath(String fanartPath) {
125 | this.fanartPath = fanartPath;
126 | }
127 |
128 | public String getPosterPath() {
129 | return posterPath;
130 | }
131 |
132 | public void setPosterPath(String posterPath) {
133 | this.posterPath = posterPath;
134 | }
135 |
136 | public List getEpisodes() {
137 | return episodes;
138 | }
139 |
140 | public void setEpisodes(List episodes) {
141 | this.episodes = episodes;
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/widget/ObservableScrollView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.widget;
19 |
20 | import android.content.Context;
21 | import android.util.AttributeSet;
22 | import android.widget.ScrollView;
23 |
24 | public class ObservableScrollView
25 | extends ScrollView
26 | {
27 | public static interface OnScrollChangedListener {
28 | public void onScrollChanged(int l, int t, int oldl, int oldt);
29 | }
30 |
31 | private OnScrollChangedListener listener;
32 |
33 | public ObservableScrollView(Context context, AttributeSet attrs) {
34 | super(context, attrs);
35 | }
36 |
37 | @Override
38 | protected void onScrollChanged(int l, int t, int oldl, int oldt) {
39 | super.onScrollChanged(l, t, oldl, oldt);
40 |
41 | if (listener != null) {
42 | listener.onScrollChanged(l, t, oldl, oldt);
43 | }
44 | }
45 |
46 | public void setOnScrollChangedListener(OnScrollChangedListener listener) {
47 | this.listener = listener;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/widget/WrapContentListView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.widget;
19 |
20 | import android.content.Context;
21 | import android.util.AttributeSet;
22 | import android.view.View;
23 | import android.widget.ListAdapter;
24 | import android.widget.ListView;
25 |
26 | public class WrapContentListView
27 | extends ListView
28 | {
29 | public WrapContentListView(Context context, AttributeSet attrs) {
30 | super(context, attrs);
31 | }
32 |
33 | @Override
34 | public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
35 | int height = 0;
36 |
37 | final ListAdapter adapter = getAdapter();
38 | if (adapter != null) {
39 | for (int i = 0; i < adapter.getCount(); i++) {
40 | View item = adapter.getView(i, null, this);
41 |
42 | if (item != null) {
43 | final int unspecified =
44 | MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
45 | item.measure(widthMeasureSpec, unspecified);
46 |
47 | height += item.getMeasuredHeight();
48 | height += getDividerHeight();
49 | }
50 | }
51 | }
52 |
53 | heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
54 | MeasureSpec.EXACTLY);
55 |
56 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/redcoracle/episodes/widget/WrapContentViewPager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Jamie Nicol
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | package com.redcoracle.episodes.widget;
19 |
20 | import android.content.Context;
21 | import android.util.AttributeSet;
22 | import android.view.View;
23 |
24 | import androidx.fragment.app.Fragment;
25 | import androidx.fragment.app.FragmentPagerAdapter;
26 | import androidx.viewpager.widget.ViewPager;
27 |
28 | public class WrapContentViewPager
29 | extends ViewPager
30 | {
31 | public WrapContentViewPager(Context context, AttributeSet attrs) {
32 | super(context, attrs);
33 | }
34 |
35 | @Override
36 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
37 | final FragmentPagerAdapter adapter = (FragmentPagerAdapter)getAdapter();
38 | final Fragment fragment =
39 | (Fragment)getAdapter().instantiateItem(this, getCurrentItem());
40 |
41 | if (fragment != null) {
42 | final View view = fragment.getView();
43 |
44 | if (view != null) {
45 | view.measure(widthMeasureSpec,
46 | MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
47 |
48 | final int height = Math.max(view.getMeasuredHeight(),
49 | getSuggestedMinimumHeight());
50 | heightMeasureSpec =
51 | MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
52 | }
53 | }
54 |
55 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
56 | }
57 |
58 | public int getMinimumHeightPlease() {
59 | // getMinimumHeight() is only API level >= 16, and
60 | // getSuggestedMinimumHeight() is protected.
61 | return getSuggestedMinimumHeight();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/res/color/tab_text.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_menu_add_show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/drawable-hdpi/ic_menu_add_show.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_menu_filter_shows_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/drawable-hdpi/ic_menu_filter_shows_list.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/shows_list_gradient.xml:
--------------------------------------------------------------------------------
1 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_menu_add_show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/drawable-mdpi/ic_menu_add_show.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_menu_filter_shows_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/drawable-mdpi/ic_menu_filter_shows_list.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/blank_show_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/drawable-nodpi/blank_show_banner.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_menu_add_show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/drawable-xhdpi/ic_menu_add_show.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_menu_filter_shows_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/drawable-xhdpi/ic_menu_filter_shows_list.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_menu_add_show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/drawable-xxhdpi/ic_menu_add_show.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_menu_filter_shows_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/drawable-xxhdpi/ic_menu_filter_shows_list.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/archived_toggle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gradient.xml:
--------------------------------------------------------------------------------
1 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_show_archived.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_show_starred.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_show_unarchived.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_show_unstarred.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/starred_toggle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/watched_progress.xml:
--------------------------------------------------------------------------------
1 |
3 | -
5 |
6 |
8 |
9 |
10 | -
12 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/about_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
14 |
20 |
28 |
34 |
40 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/add_show_preview_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/add_show_preview_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
17 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/add_show_search_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
26 |
27 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/add_show_search_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/add_show_search_results_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/episode_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/episode_details_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
22 |
30 |
39 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/episodes_list_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/episodes_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
15 |
24 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/main_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/season_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/seasons_list_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/seasons_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
23 |
27 |
32 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/settings_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/show_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
22 |
23 |
29 |
30 |
35 |
36 |
42 |
43 |
44 |
54 |
55 |
62 |
63 |
64 |
65 |
70 |
71 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/show_details_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
16 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/show_notes_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/shows_list_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/shows_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
14 |
15 |
20 |
21 |
36 |
37 |
47 |
58 |
62 |
67 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/add_show_preview_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/season_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/show_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/shows_list_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/values-bg/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 | Първо излъчено: %s
27 | Не може да се добави %s в библиотеката
28 | Архивирането е завършено: \'%s\"
29 | Не може да се архивира библиотеката
30 | Версия %s (Къмит на %s)
31 | Интерфейс
32 | Серия за автоматично обновяване
33 | Уведомяване при синхронизиране показва
34 | Показване на синхронизирането
35 | %1$d от %2$d епизоди, наблюдавани
36 | Гледани
37 | (+ %d предстоящи)
38 | Преглед
39 | Бележки
40 | Следващата
41 | %s вече в библиотека
42 | %s добавен към библиотеката
43 | Настройки
44 | Специални
45 | Сезон %d
46 | "%1$02dx%2$02d - "
47 | Библиотеката е възстановена
48 | Не може да се възстанови библиотеката
49 | Възстановяване от архив
50 | Не са намерени архиви в папка \'%s\'.
51 | Показва най-новия сезон
52 | Обратен ред на сортиране
53 | Език
54 | Само при неомерени връзки
55 | Автоматично обновяване
56 | Интервал
57 | Премахни показването от архива
58 | Архивно шоу
59 | Епизодите са софтуер за GPLv3+. Моля, пиши bugs, писане на код, превеждайте или направете всичко друго, което можете да направите, за да помогнете!
60 | Следете кои епизоди сте гледали от любимите си предавания
61 | Архивиране на библиотека
62 | Добавяне %s към библиотеката
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-cs/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Sledujte, které epizody jste sledovali z vašich oblíbených pořadů
4 | Lägg till %s i biblioteket
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Verfolge, welche Episoden Deiner Lieblingssendungen Du gesehen hast
4 | Benutzeroberfläche
5 | Serien automatisch aktualisieren
6 | %1$d von %2$d Folgen gesehen
7 | Gesehen
8 | (+ %d angekündigt)
9 | Übersicht
10 | Nächste
11 | Folgen
12 | %s bereits in der Bibliothek
13 | %s zur Bibliothek hinzugefügt
14 | Einstellungen
15 | Specials
16 | Staffel %d
17 | "%1$02dx%2$02d - "
18 | Bibliothek wiederhergestellt
19 | Bibliothek konnte nicht wiederhergestellt werden
20 | Aus einer Sicherung wiederherstellen
21 | Keine Datensicherungen im Ordner „%s“ gefunden
22 | Neueste Staffel zuerst
23 | Reihenfolge umkehren
24 | Sprache
25 | Nur bei nicht gemessenen Verbindungen
26 | Automatisch aktualisieren
27 | Intervall
28 | Serie aus Archiv entfernen
29 | Serie archivieren
30 | Serie aus Favoriten entfernen
31 | Serie favorisieren
32 | Einstellungen
33 | Datensicherung wiederherstellen
34 | Serie aktualisieren
35 | Serien aktualisieren
36 | Folge als gesehen markieren
37 | Folge als ungesehen markieren
38 | Staffel als gesehen markieren
39 | Staffel als ungesehen markieren
40 | Angekündigte
41 | Angefangene
42 | Archivierte
43 | Favoriten
44 | Alle
45 | Serien filtern
46 | Serie löschen
47 | Datensicherung erstellen
48 | Serie hinzufügen
49 | Serie hinzufügen
50 | Neue Serie suchen
51 | Über
52 | Erstausstrahlung: %s
53 | %s konnte nicht zur Bibliothek hinzugefügt werden
54 | Datensicherung fertiggestellt: „%s“
55 | Datensicherung der Bibliothek konnte nicht erstellt werden
56 | %s wird zur Bibliothek hinzugefügt
57 | Über
58 | Episodes ist freie Software unter GPLv3+. Hilf gern mit, indem Du Fehler meldest, Code oder Übersetzungen schreibst!
59 | Synchronisierung anzeigen
60 | Benachrichtigung beim Synchronisieren von Sendungen
61 | Anmerkungen
62 | Version %s (Commit %s)
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-eo/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Fasado
4 | %1$d el %2$d epizodoj spektiĝis
5 | Spektita
6 | Superrigardo
7 | Notoj
8 | Epizodoj
9 | %s jam en biblioteko
10 | %s aldonita al biblioteko
11 | Agordoj
12 | Sezono %d
13 | Biblioteko restaŭriĝis
14 | Ne povis restaŭri bibliotekon
15 | Restaŭri savkopion
16 | Neniu savkopio troviĝis en la dosierujo \'%s\'.
17 | Lingvo
18 | Elarkivigi spektaĵon
19 | Enarkivigi spektaĵon
20 | Malmarki kiel plej ŝatatan
21 | Marki kiel plej ŝatatan
22 | Agordoj
23 | Marki spektaĵon kiel spektitan
24 | Marki spektaĵon kiel nespektitan
25 | Marki sezonon kiel spektita
26 | Marki sezonon kiel nespektita
27 | En arkivo
28 | Plej ŝatataj
29 | Ĉiuj
30 | Forigi spektaĵon
31 | Savkopii bibliotekon
32 | Aldoni spektaĵon al biblioteko
33 | Aldoni novan spektaĵon al biblioteko
34 | Serĉi novan spektaĵon
35 | Pri
36 | Ne povis aldoni %s al biblioteko
37 | Savkopio kompleta: \'%s\'
38 | Ne povis savkopii bibliotekon
39 | Aldonante %s al biblioteko
40 | Pri
41 | Filtri spektaĵojn
42 | Versio %s (Enmeto %s)
43 | Specialaĵoj
44 | "%1$02d×%2$02d - "
45 | Intervalo
46 | Prezentata
47 | Prezentota
48 | (+ %d prezentota(j))
49 | Unua Prezentado: %s
50 | Sciigo pri sinkronigo de spektaĵoj
51 | Reŝargi spektaĵon
52 | Reŝargi ĉiujn spektaĵojn
53 | Episodes estas kopilasita libera programo sub la permesiloj GPLv3+. Bonvolu raporti cimojn, skribi kodojn, traduki aŭ helpi ĉiel ajn!
54 | Marku la spektitajn epizodojn de viaj plej ŝatataj spektaĵoj
55 | Aŭtomate reŝargi spektaĵon
56 | Sekva
57 | Sciigi pri sinkronigo
58 | Nur per nemezurataj retkonektoj
59 | Aŭtomate reŝargata
60 | Montri unue la plej novan sezonon
61 | Mala ordo
62 | Restaŭri savkopion
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | (+ %d próximamente)
4 | Descripción
5 | Sólo en conexiones no medidas
6 | Próximamente
7 | En emisión
8 | Emitida por primera vez: %s
9 | Episodes es software libre copyleft bajo licencia GPLv3+. ¡Por favor registra bugs, escribe código, traduce o haz cualquier cosa que puedas para ayudar!
10 | Mantén un registro de qué episodios de tus series favoritas has visto
11 | Versión %s (Commit %s)
12 | Interfaz
13 | Actualizar series automáticamente
14 | Notificación cuando se sincronizan series
15 | Sincronizar serie
16 | %1$d de %2$d episodios vistos
17 | Visto
18 | Notas
19 | Siguiente
20 | Episodios
21 | %s ya está en la biblioteca
22 | %s añadida a la biblioteca
23 | Ajustes
24 | Especiales
25 | Temporada %d
26 | "%1$02dx%2$02d - "
27 | Biblioteca restaurada
28 | No se ha podido restaurar la biblioteca
29 | Restaurar desde copia de seguridad
30 | No se han encontrado copias de seguridad en la carpeta \'%s\'.
31 | Muestra primero la temporada más nueva
32 | Orden inverso
33 | Lenguaje
34 | Actualización automática activada
35 | Intervalo
36 | Quitar serie del archivo
37 | Archivar serie
38 | No destacar serie
39 | Destacar serie
40 | Ajustes
41 | Restaurar desde copia de seguridad
42 | Actualizar serie
43 | Actualizar todas las series
44 | Marcar serie como vista
45 | Marcar serie como no vista
46 | Marcar temporada como vista
47 | Marcar temporada como no vista
48 | Archivadas
49 | Destacadas
50 | Todas
51 | Filtrar series
52 | Borrar serie
53 | Realizar copia de seguridad de la biblioteca
54 | Añadir serie a la biblioteca
55 | Añadir nueva serie a la biblioteca
56 | Buscar una nueva serie
57 | Acerca de
58 | No se ha podido añadir %s a la biblioteca
59 | Copia de seguridad completada: \'%s\'
60 | No se ha podido realizar la copia de seguridad de la biblioteca
61 | Añadiendo %s a la biblioteca
62 | Acerca de
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-eu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bertsioa %s (Egin %s)
4 | Interfazea
5 | Automatikoki freskatu serieak
6 | Ikuskizunak sinkronizatzean jakinarazpena
7 | Erakutsi sinkronizazioa
8 | %1$d of %2$d ikusitako pasarteak
9 | Ikusita
10 | (+ %d datozenak)
11 | Ikuspegi orokorra
12 | Oharrak
13 | Hurrengoa
14 | Episodes
15 | %s dagoeneko liburutegian
16 | %s liburutegian gehitu da
17 | Ezarpenak
18 | Bereziak
19 | Denboraldia %d
20 | "%1$02dx%2$02d - "
21 | Liburutegia zaharberritu da
22 | Ezin izan da liburutegia leheneratu
23 | Leheneratu segurtasun kopiatik
24 | Ez da babeskopiarik aurkitu \'%s\' karpetan.
25 | Denboraldi berriena erakusten du lehenengo
26 | Alderantziz ordenatzeko ordena
27 | Hizkuntza
28 | Meditu gabeko konexioetan soilik
29 | Freskatze automatikoa aktibatuta
30 | Tartea
31 | Kendu ikuskizuna artxibotik
32 | Artxibo ikuskizuna
33 | Erakutsi izarra
34 | Izar ikuskizuna
35 | Ezarpenak
36 | Leheneratu segurtasun kopiatik
37 | Freskatu ikuskizuna
38 | Freskatu ikuskizun guztiak
39 | Markatu ikuskizuna ikusi bezala
40 | Markatu ikuskizuna ikusi gabeko moduan
41 | Markatu denboraldia ikusitako moduan
42 | Markatu denboraldia ikusi gabeko moduan
43 | Datozenak
44 | Martxan
45 | Artxibatuta
46 | Izarrak
47 | Guztiak
48 | Iragazkien ikuskizunak
49 | Ezabatu ikuskizuna
50 | Egin liburutegiaren babeskopia
51 | Gehitu ikuskizuna liburutegian
52 | Gehitu ikuskizun berria liburutegian
53 | Bilatu ikuskizun berria
54 | Buruz
55 | Lehenengo igorpena: %s
56 | Ezin izan da %s gehitu liburutegian
57 | Babeskopia osatua: \'%s\'
58 | Ezin izan da liburutegiaren segurtasun kopia egin
59 | liburutegian %s gehitzen
60 | Buruz
61 | Episodes copylefted libre software lizentziadun GPLv3 + da. Mesedez, bidali akatsak, idatzi kodea, itzuli edo egin ezazu laguntzeko duzun guztia!
62 | Jarrai itzazu zure saio gogokoenen atalak ikusi dituzunak
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | À propos
4 | Première diffusion : %s
5 | À propos
6 | Ajout de %s à la bibliothèque
7 | Episodes est un logiciel libre sous licence GPLv3+. Vous pouvez signaler des erreurs, écrire du code, traduire ou faire quoi que ce soit d\'autre pour contribuer !
8 | Gardez une trace des épisodes que vous avez regardés dans vos séries préférées
9 | Ajouter la série à la bibliothèque
10 | Ajouter une nouvelle série à la bibliothèque
11 | Rechercher une nouvelle série
12 | Impossible d\'ajouter %s à la bibliothèque
13 | Sauvegarde terminée : « %s »
14 | Impossible de sauvegarder la bibliothèque
15 | Interface
16 | Actualiser automatiquement les séries
17 | Notification lors de la synchronisation des séries
18 | Synchronisation de la série
19 | %1$d épisode sur %2$d regardé
20 | Regardé
21 | (+ %d à venir)
22 | Aperçu
23 | Notes
24 | Suivant
25 | Épisodes
26 | %s déjà dans la bibliothèque
27 | %s ajouté à la bibliothèque
28 | Paramètres
29 | Spécial
30 | Saison %d
31 | "%1$02dx%2$02d - "
32 | Bibliothèque restaurée
33 | Impossible de restaurer la bibliothèque
34 | Restaurer à partir d\'une sauvegarde
35 | Aucune sauvegarde trouvée dans le dossier « %s ».
36 | Affiche la dernière saison en premier
37 | Inverser l\'ordre de tri
38 | Langue
39 | Seulement sur les connexions non limitées
40 | Actualisation auto activée
41 | Intervale
42 | Retirer la série des archives
43 | Archiver la série
44 | Retirer la série des favoris
45 | Ajouter la série aux favoris
46 | Paramètres
47 | Restaurer une sauvegarde
48 | Actualiser la série
49 | Actualiser toutes les séries
50 | Marquer la série comme regardée
51 | Marquer la série comme non regardée
52 | Marquer la saison comme regardée
53 | Marquer la saison comme non regardée
54 | À venir
55 | En cours
56 | Archivé
57 | Favoris
58 | Tout
59 | Filtrer les séries
60 | Supprimer la série
61 | Restaurer la bibliothèque
62 | %s verzió (Commit %s)
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-hr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Prikaži sinkronizaciju
4 | Označi sezonu kao pogledanu
5 | Filtriraj emisije
6 | Odznači emisiju
7 | Obnovi iz sigurnosne kopije
8 | Sezona %d
9 | Automatsko aktualiziranje uključeno
10 | Označi emisiju
11 | Označi emisiju kao pogledanu
12 | Prvi put emitirano: %s
13 | (+ %d predstojeće)
14 | Spremi sigurnosnu kopiju biblioteke
15 | Ukloni emisjiu iz arhive
16 | Prati stanja gledanja epizoda tvojih omiljenih emisija
17 | Emisija „%s” je dodana u biblioteku
18 | Dodaj novu emisiju u biblioteku
19 | Obrni redoslijed
20 | Pogledano
21 | Epizode
22 | Obnovi iz sigurnosne kopije
23 | Aktualiziraj emisiju
24 | Predstojeće
25 | Neuspjelo spremanje sigurnosne kopije biblioteke
26 | „Epizode” je copyleft slobodni softver s licencom GPLv3+. Prijavi greške, programiraj, prevodi ili pomogni na bilo koji drugi način!
27 | Pregled
28 | Emisija „%s” se već nalazi u biblioteci
29 | Prikazuje najnoviju sezonu na prvom mjestu
30 | Arhivirane
31 | Napomene
32 | Sljedeća
33 | Postavke
34 | Neuspjelo obnavljanje biblioteke
35 | Jezik
36 | Traži novu emisiju
37 | Informacije
38 | Nadolazeće
39 | Označi emisiju kao nepogledanu
40 | Obavijesti pri sinkronizaciji emisija
41 | Aktualiziraj sve emisije
42 | Informacije
43 | Pogledanih epizoda: %1$d od %2$d
44 | Biblioteka obnovljena
45 | Postavke
46 | Označene
47 | Označi sezonu kao nepogledanu
48 | Izbriši emisiju
49 | Samo na vezama bez ograničenja
50 | Interval
51 | Arhiviraj emisiju
52 | Sučelje
53 | Emisija „%s” se dodaje u biblioteku
54 | Neuspjelo dodavanje emisije „%s” u biblioteku
55 | Sve
56 | Dodaj emisiju u biblioteku
57 | Automatsko aktualiziranje serija
58 | Specijalne
59 | Sigurnosna kopija gotova: „%s”
60 | U mapi „%s” nema sigurnosnih kopija.
61 | "%1$02d × %2$02d - "
62 | Verzija %s (Izmjena %s)
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Aggiunta di %s alla libreria
4 | Informazioni
5 | Episodes è un software libero con copyleft di licenza GPLv3+. Per favore, segnalate errori, scrivete codice, traducete o fate qualsiasi altra cosa per aiutare!
6 | Tieni traccia di quali episodi hai guardato dei tuoi programmi preferiti
7 | Versione %s (Commit %s)
8 | Interfaccia
9 | Aggiornamento automatico serie
10 | Notifica quando le serie si sincronizzano
11 | Sincronizzazione della serie
12 | %1$d di %2$d episodi guardati
13 | Guardato
14 | (+ %d prossimamente)
15 | Panoramica
16 | Note
17 | Successivo
18 | Episodes
19 | %s già nella raccolta
20 | %s aggiunto alla raccolta
21 | Impostazioni
22 | Speciali
23 | Stagione %d
24 | "%1$02dx%2$02d - "
25 | Raccolta ripristinata
26 | Non è stato possibile ripristinare la raccolta
27 | Ripristina da un backup
28 | Nessun backup trovato nella cartella «%s».
29 | Visualizza prima la stagione più recente
30 | Invertisci l\'ordine di ordinamento
31 | Lingua
32 | Solo con connessioni non misurate
33 | Aggiornamento automatico abilitato
34 | Periodicità
35 | Rimuovi la serie dall\'archivio
36 | Archivia la serie
37 | Rimuovi la serie dai favoriti
38 | Aggiungi la serie ai favoriti
39 | Impostazioni
40 | Ripristino da backup
41 | Aggiorna la serie
42 | Aggiorna tutte le serie
43 | Segna la serie come guardata
44 | Segna come non guardato
45 | Segna la stagione come guardato
46 | Segna la stagione come non guardato
47 | Prossimamente
48 | In corso
49 | Archiviato
50 | Stellato
51 | Tutto
52 | Filtra le serie
53 | Elimina la serie
54 | Backup della raccolta
55 | Aggiungi la serie alla raccolta
56 | Aggiungi una nuova serie alla raccolta
57 | Cerca una nuova serie
58 | Informazioni
59 | Prima messa in onda: %s
60 | Impossibile aggiungere %s alla raccolta
61 | Backup completato: «%s»
62 | Impossibile eseguire il backup della raccolta
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-nb-rNO/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Grensesnitt
4 | Auto-gjenoppfrisk serier
5 | Merknad ved synkronisering av programmer
6 | Vis synkronisering
7 | %1$d av %2$d episoder sett
8 | Sett
9 | (+ %d kommende)
10 | Oversikt
11 | Notater
12 | Neste
13 | Episoder
14 | %s allerede i bibliotek
15 | %s lagt til i bibliotek
16 | Innstillinger
17 | Sesong %d
18 | Spesialsendinger
19 | "%1$02dx%2$02d - "
20 | Bibliotek gjenopprettet
21 | Klarte ikke å gjenopprette bibliotek
22 | Gjenopprett fra sikkehetskopi
23 | Fant ingen sikkerhetskopier i «%s»-mappen.
24 | Vis nyeste sesong først
25 | Reverser sorteringsrekkefølge
26 | Språk
27 | Kun på ubegrensede tilkoblinger
28 | Auto-gjenoppfrisking påskrudd
29 | Intervall
30 | Fjern program fra arkiv
31 | Arkiver program
32 | Fjern stjernemerking
33 | Stjernemerk program
34 | Innstillinger
35 | Gjenopprett fra sikkerhetskopi
36 | Gjenoppfrisk program
37 | Gjenoppfrisk alle programmer
38 | Marker program som sett
39 | Marker program som usett
40 | Marker sesong som sett
41 | Marker sesong som usett
42 | Kommende
43 | Underveis
44 | Arkivert
45 | Stjernemerkede
46 | Alle
47 | Filtrer programmer
48 | Slett program
49 | Sikkerhetskopier bibliotek
50 | Legg til program i bibliotek
51 | Legg til nytt program i bibliotek
52 | Søk etter nytt program
53 | Om
54 | Først sendt: %s
55 | Klarte ikke å legge til %s i biblioteket
56 | Sikkerhetskopi utført: «%s»
57 | Klarte ikke å sikkerhetskopiere bibliotek
58 | Legger til %s i biblioteket
59 | Om
60 | Episodes er gemenlig fri programvare lisensiert GPLv3+. Send inn feil, skriv kode, oversett og gjør hva du kan for å hjelpe til.
61 | Hold orden på hvilke episoder du har sett av dine favoritt-programmer
62 | Versjon %s (innsendelse %s)
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Интерфейс
4 | Автообновление серий
5 | Уведомление при синхронизации шоу
6 | Показать синхронизацию
7 | %1$d из %2$d эпизодов просмотрено
8 | Просмотрено
9 | (+ %d предстоящие)
10 | Обзор
11 | Примечания
12 | Следующий
13 | Эпизоды
14 | %s уже в библиотеке
15 | %s добавлен в библиотеку
16 | Настройки
17 | Specials
18 | Сезон %d
19 | "%1$02dx%2$02d - "
20 | Библиотека восстановлена
21 | Не удалось восстановить библиотеку
22 | Восстановить из резервной копии
23 | В папке \'%s\' нет резервных копий.
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 | Первый эфир: %s
55 | Не удалось добавить %s в библиотеку
56 | Резервное копирование завершено: \'%s\'
57 | Не удалось создать резервную копию библиотеки
58 | Добавление %s в библиотеку
59 | О приложении
60 | Episodes - это бесплатное программное обеспечение с авторским левом под лицензией GPLv3 +. Пожалуйста, сообщайте об ошибках, пишите код, переводите или делайте что-нибудь ещё, чтобы помочь!
61 | Следите за тем, какие серии любимых шоу вы смотрели
62 | Версия %s (Изменение %s)
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sv/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Version %s (åtagande %s)
4 | Gränssnitt
5 | %1$d av %2$d avsnitt sedda
6 | "%1$02dx%2$02d - "
7 | Avisering när program synkroniseras
8 | Programsynkronisering
9 | Sedda
10 | Överblick
11 | Anteckningar
12 | Nästa
13 | Avsnitt
14 | %s redan i biblioteket
15 | %s lades till i biblioteket
16 | Inställningar
17 | Säsong %d
18 | Biblioteket återställdes
19 | Kunde inte återställa bibliotek
20 | Återställ från säkerhetskopia
21 | Inga säkerhetskopior hittades i mappen \'%s\'.
22 | Visar den nyaste säsongen först
23 | Omvänd sorteringsordning
24 | Språk
25 | Endast på obegränsade anslutningar
26 | Automatisk uppdatering på
27 | Intervall
28 | Ta bort program från arkiv
29 | Arkivera program
30 | Sluta stjärnmarkera program
31 | Stjärnmarkera program
32 | Inställningar
33 | Återställ från säkerhetskopia
34 | Uppdatera program
35 | Uppdatera alla program
36 | Kommande
37 | Pågående
38 | Arkiverade
39 | Stjärnmärkta
40 | Alla
41 | Filtrera program
42 | Ta bort program
43 | Säkerhetskopiera biblioteket
44 | Lägg till program i biblioteket
45 | Lägg till program i biblioteket
46 | Sök efter nytt program
47 | Om
48 | Sändes först: %s
49 | Kunde inte lägga till %s i biblioteket
50 | Säkerhetskopieringen färdig: \'%s\'
51 | Kunde inte säkerhetskopiera biblioteket
52 | Lägger till %s i biblioteket
53 | Om
54 | (+ %d kommande)
55 | Håll koll på vilka avsnitt du har tittat på av dina favoritprogram
56 | Episodes är copylefted libre software licensierad GPLv3+. Var snäll och skicka in felrapporter, skriv kod, översätt eller gör vad du kan för att hjälpa till!
57 | Markera säsong som osedd
58 | Markera säsong som sedd
59 | Markera program som osett
60 | Markera program som sett
61 | Specialavsnitt
62 | Automatisk uppdatering av serier
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | "%1$02dx%2$02d - "
4 | Sürüm %s (Kaydetme %s)
5 | Arayüz
6 | Dizileri otomatik yenile
7 | Şovları senkronize ederken bildirim
8 | Senkronizasyonu göster
9 | %2$d bölümden %1$d görüldü
10 | İzlendi
11 | (+%d yakında)
12 | Genel Bakış
13 | Notlar
14 | Sıradaki
15 | Bölümler
16 | %s zaten kitaplıkta
17 | %s kitaplığa eklendi
18 | Ayarlar
19 | Özel
20 | Sezon %d
21 | Kitaplık geri yüklendi
22 | Kitaplık geri yüklenemedi
23 | Yedekten geri yükle
24 | \'%s\' klasöründe yedek bulunamadı.
25 | Önce en yeni sezonu görüntüler
26 | Ters sıralama düzeni
27 | Dil
28 | Yalnızca ölçülmemiş bağlantılarda
29 | Otomatik yenileme açık
30 | Aralık
31 | Diziyi arşivden kaldır
32 | Diziyi arşivle
33 | Gösterinin yıldızını kaldır
34 | Gösteriyi yıldızla
35 | Ayarlar
36 | Yedekten geri yükle
37 | Diziyi yenile
38 | Tüm dizileri yenile
39 | Diziyi izlenmiş olarak işaretle
40 | Diziyi izlenmemiş olarak işaretle
41 | Sezonu izlendi olarak işaretle
42 | Sezonu izlenmemiş olarak işaretle
43 | Yakında
44 | Yolda
45 | Arşivlendi
46 | Yıldızlı
47 | Hepsi
48 | Filtrele
49 | Diziyi sil
50 | Kitaplığı yedekle
51 | Kitaplığa dizi ekle
52 | Kitaplığa yeni dizi ekle
53 | Yeni dizi ara
54 | Hakkında
55 | İlk Yayınlanma Tarihi: %s
56 | %s kitaplığa eklenemedi
57 | Yedekleme tamamlandı: \'%s\'
58 | Kitaplık yedeklenemedi
59 | %s kitaplığa ekleniyor
60 | Hakkında
61 | Episodes, GPLv3+ lisanslı copyleft özgür yazılımdır. Lütfen hataları bildirin, kod yazın, tercüme edin veya yardım etmek için elinizden gelen her şeyi yapın!
62 | En sevdiğiniz dizilerin hangi bölümlerini izlediğinizi takip edin
63 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - Daily
5 | - Twice weekly
6 | - Weekly
7 | - Fortnightly
8 |
9 |
10 | - 24
11 | - 84
12 | - 168
13 | - 336
14 |
15 |
16 | - Chinese
17 | - Croation
18 | - Czech
19 | - Dansk
20 | - Deutsch
21 | - English
22 | - Español
23 | - Français
24 | - Greek
25 | - Hebrew
26 | - Italiano
27 | - Japanese
28 | - Korean
29 | - Magyar
30 | - Nederlands
31 | - Norsk
32 | - Polski
33 | - Portuguese
34 | - Russian
35 | - Slovenian
36 | - Suomeksi
37 | - Svenska
38 | - Turkish
39 |
40 |
41 | - zh
42 | - hr
43 | - cs
44 | - da
45 | - de
46 | - en
47 | - es
48 | - fr
49 | - el
50 | - he
51 | - it
52 | - ja
53 | - ko
54 | - hu
55 | - nl
56 | - no
57 | - pl
58 | - pt
59 | - ru
60 | - sl
61 | - fi
62 | - sv
63 | - tr
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #009688
4 | #212121
5 | #181818
6 | #bdbdbd
7 | @color/accent
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 200dp
4 | 16dp
5 | 24sp
6 | 48dp
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Keep track of which episodes you\'ve watched of your favourite shows
4 | Episodes is copylefted libre software licensed GPLv3+. Please file bugs, write code, translate or do anything else you can to help!
5 | About
6 | This product uses the TMDB API but is not endorsed or certified by TMDB.
7 | https://github.com/red-coracle/episodes
8 | Episodes
9 | Adding %s to library
10 | Could not back up library
11 | Back-up complete: \'%s\'
12 | Could not add %s to library
13 | First Aired: %s
14 | About
15 | Search for new show
16 | Add new show to library
17 | Add show to library
18 | Back up library
19 | Delete show
20 | Filter shows
21 | All
22 | Starred
23 | Archived
24 | Underway
25 | Upcoming
26 | Mark season as unwatched
27 | Mark season as watched
28 | Mark show as unwatched
29 | Mark show as watched
30 | Refresh all shows
31 | Refresh show
32 | Restore from backup
33 | Settings
34 | Star show
35 | Unstar show
36 | Archive show
37 | Remove show from archive
38 | Interval
39 | Auto-refresh on
40 | Only on unmetered connections
41 | Language
42 | Reverse sorting order
43 | Displays the newest season first
44 | No backups found in \'%s\' folder.
45 | Restore from backup
46 | Could not restore library
47 | Library restored
48 | "%1$02dx%2$02d - "
49 | Season %d
50 | Specials
51 | Settings
52 | %s added to library
53 | %s already in library
54 | Episodes
55 | Next
56 | Notes
57 | Overview
58 | (+ %d upcoming)
59 | Watched
60 | %1$d of %2$d episodes seen
61 | Show sync
62 | Notification when syncing shows
63 | Auto-refresh series
64 | Interface
65 | Version %s (Commit %s)
66 | No search results found
67 | Metadata provider has switched to TMDB. We recommend backing up your database before refreshing all metadata. Press Continue to proceed with refreshing all shows or Cancel to return.
68 | Metadata Provider Change
69 | Continue
70 | Cancel
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
16 |
17 |
22 |
23 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
17 |
18 |
19 |
21 |
25 |
33 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/assets/feature-graphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/assets/feature-graphic.png
--------------------------------------------------------------------------------
/assets/hi-res-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/assets/hi-res-icon.png
--------------------------------------------------------------------------------
/assets/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/assets/screenshot-1.png
--------------------------------------------------------------------------------
/assets/screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/assets/screenshot-2.png
--------------------------------------------------------------------------------
/assets/screenshot-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/assets/screenshot-3.png
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenCentral()
4 | google()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:7.3.0'
8 | }
9 | }
10 |
11 | allprojects {
12 | repositories {
13 | mavenCentral()
14 | google()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0014.txt:
--------------------------------------------------------------------------------
1 | - Upgrade SDK and gradle versions
2 | - Switch from support library to androidx
3 | - Replace universal-image-loader with Glide
4 | - Use newer OkHttp & TVDB client versions
5 | - Fix sync notification/progress
6 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0015.txt:
--------------------------------------------------------------------------------
1 | - Replace deprecated AsyncTask
2 | - Searching and adding shows now uses language preference
3 | - Use poster image if fanart image is unavailable
4 | - Display loading indicator when fetching fanart/poster image
5 | - Add preference categories and use switches instead of checkboxes
6 | - Update dependencies and gradle
7 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0016.txt:
--------------------------------------------------------------------------------
1 | - Add filter for upcoming shows
2 | - Fix app crash when searching for shows
3 | - Add language column to episodes table if it does not exist
4 | - Update dependencies/gradle
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0017.txt:
--------------------------------------------------------------------------------
1 | - Added translations for Croatian, French, German, Norwegian Bokmål, Russian, and Spanish. Many thanks to the contributors on Weblate!
2 | - Add version and commit info to the About screen
3 | - Use the configured language when downloading show data
4 | - Update dependencies/gradle
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0018.txt:
--------------------------------------------------------------------------------
1 | - New and updated translations
2 |
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0019.txt:
--------------------------------------------------------------------------------
1 | - Fix searching for shows to add
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0020.txt:
--------------------------------------------------------------------------------
1 | - Display a message when a search returns no results
2 | - Show a loading spinner when searching for new shows
3 | - When marking a season as watched, only mark aired episodes
4 | - Updated dependencies
5 | - Updated translations
6 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0021.txt:
--------------------------------------------------------------------------------
1 | - Fix back button on season details
2 | - Update R8 configuration
3 | - Fix crash on Android 12
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0022.txt:
--------------------------------------------------------------------------------
1 | - Update badges in README
2 | - New launcher icon
3 | - Use storage framework on API19+
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0023.txt:
--------------------------------------------------------------------------------
1 | - Final release with TVDB as metadata provider
2 | - Target version 33 (Android 13)
3 | - Raise minimum version to 21 (Android L)
4 | - Request notification permission on Android 13+
5 | - Update gradle version
6 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0024.txt:
--------------------------------------------------------------------------------
1 | - Switch to TMDB as metadata provider
2 | - Add support for themed app icons
3 | - Fix for null/zero TVDB ID
4 | - Update setup-java CI action
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/0025.txt:
--------------------------------------------------------------------------------
1 | - Fix sorting in shows list
2 | - Update star/archive icons to improve visibility
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | Keep track of which episodes you’ve watched of your favourite TV shows.
2 | This product uses the TMDB API but is not endorsed or certified by TMDB.
3 |
4 | Anti-Feature: NonFreeNet - uses a non-free network service which is impossible, or not easy to replace without rebuilding the app
5 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | Keep track of which episodes you’ve watched of your favourite TV shows.
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | Episodes
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.useAndroidX=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/red-coracle/episodes/fac7e844ff9e537935c91c9294f9aa12a3e92975/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionSha256Sum=db9c8211ed63f61f60292c69e80d89196f9eb36665e369e7f00ac4cc841c2219
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 |
35 | @rem Find java.exe
36 | if defined JAVA_HOME goto findJavaFromJavaHome
37 |
38 | set JAVA_EXE=java.exe
39 | %JAVA_EXE% -version >NUL 2>&1
40 | if "%ERRORLEVEL%" == "0" goto init
41 |
42 | echo.
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44 | echo.
45 | echo Please set the JAVA_HOME variable in your environment to match the
46 | echo location of your Java installation.
47 |
48 | goto fail
49 |
50 | :findJavaFromJavaHome
51 | set JAVA_HOME=%JAVA_HOME:"=%
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53 |
54 | if exist "%JAVA_EXE%" goto init
55 |
56 | echo.
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58 | echo.
59 | echo Please set the JAVA_HOME variable in your environment to match the
60 | echo location of your Java installation.
61 |
62 | goto fail
63 |
64 | :init
65 | @rem Get command-line arguments, handling Windows variants
66 |
67 | if not "%OS%" == "Windows_NT" goto win9xME_args
68 |
69 | :win9xME_args
70 | @rem Slurp the command line arguments.
71 | set CMD_LINE_ARGS=
72 | set _SKIP=2
73 |
74 | :win9xME_args_slurp
75 | if "x%~1" == "x" goto execute
76 |
77 | set CMD_LINE_ARGS=%*
78 |
79 | :execute
80 | @rem Setup the command line
81 |
82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
83 |
84 | @rem Execute Gradle
85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
86 |
87 | :end
88 | @rem End local scope for the variables with windows NT shell
89 | if "%ERRORLEVEL%"=="0" goto mainEnd
90 |
91 | :fail
92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
93 | rem the _cmd.exe /c_ return code!
94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
95 | exit /b 1
96 |
97 | :mainEnd
98 | if "%OS%"=="Windows_NT" endlocal
99 |
100 | :omega
101 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------