├── Android
└── PopularMovies
│ ├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values-w820dp
│ │ │ │ │ └── dimens.xml
│ │ │ │ ├── menu
│ │ │ │ │ ├── detail.xml
│ │ │ │ │ └── main.xml
│ │ │ │ ├── layout
│ │ │ │ │ ├── activity_movie_detail.xml
│ │ │ │ │ ├── activity_movies_list.xml
│ │ │ │ │ ├── fragment_movies_list.xml
│ │ │ │ │ ├── movie_item.xml
│ │ │ │ │ ├── activity_reviews.xml
│ │ │ │ │ ├── activity_trailers.xml
│ │ │ │ │ ├── trailer_item.xml
│ │ │ │ │ ├── review_item.xml
│ │ │ │ │ ├── review.xml
│ │ │ │ │ ├── trailer.xml
│ │ │ │ │ ├── fragment_movie_detail.xml
│ │ │ │ │ └── primary_movie_info.xml
│ │ │ │ └── values
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── dimens.xml
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── styles.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── ivanmagda
│ │ │ │ │ └── popularmovies
│ │ │ │ │ ├── utilities
│ │ │ │ │ ├── ConnectivityUtils.java
│ │ │ │ │ ├── json
│ │ │ │ │ │ ├── JsonUtils.java
│ │ │ │ │ │ ├── ReviewsJsonUtils.java
│ │ │ │ │ │ ├── YouTubeTrailerJsonUtils.java
│ │ │ │ │ │ └── MovieJsonUtils.java
│ │ │ │ │ ├── YouTubeTrailerUtils.java
│ │ │ │ │ ├── MovieDateUtils.java
│ │ │ │ │ ├── ImageUtils.java
│ │ │ │ │ └── MoviePersistenceUtils.java
│ │ │ │ │ ├── network
│ │ │ │ │ ├── MoviesLoader.java
│ │ │ │ │ ├── tmdb
│ │ │ │ │ │ ├── ReviewsFetchTask.java
│ │ │ │ │ │ └── TrailersFetchTask.java
│ │ │ │ │ ├── Resource.java
│ │ │ │ │ └── Webservice.java
│ │ │ │ │ ├── data
│ │ │ │ │ ├── FavoriteMoviesAdapter.java
│ │ │ │ │ ├── FavoriteMoviesLoaderCallbacksAdapter.java
│ │ │ │ │ ├── model
│ │ │ │ │ │ ├── YouTubeTrailer.java
│ │ │ │ │ │ ├── Review.java
│ │ │ │ │ │ └── Movie.java
│ │ │ │ │ ├── TrailersAdapter.java
│ │ │ │ │ ├── ReviewsAdapter.java
│ │ │ │ │ └── MovieAdapter.java
│ │ │ │ │ ├── Extras.java
│ │ │ │ │ ├── view
│ │ │ │ │ └── activity
│ │ │ │ │ │ ├── TrailersActivity.java
│ │ │ │ │ │ ├── ReviewsActivity.java
│ │ │ │ │ │ ├── MovieDetailActivity.java
│ │ │ │ │ │ └── MoviesListActivity.java
│ │ │ │ │ └── persistence
│ │ │ │ │ ├── MovieDbHelper.java
│ │ │ │ │ └── MovieContract.java
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── ivanmagda
│ │ │ │ └── popularmovies
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── ivanmagda
│ │ │ └── popularmovies
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
│ ├── settings.gradle
│ ├── .idea
│ ├── copyright
│ │ └── profiles_settings.xml
│ ├── markdown-navigator
│ │ └── profiles_settings.xml
│ ├── encodings.xml
│ ├── dictionaries
│ │ └── ivanmagda.xml
│ ├── vcs.xml
│ ├── inspectionProfiles
│ │ ├── profiles_settings.xml
│ │ └── Project_Default.xml
│ ├── modules.xml
│ ├── runConfigurations.xml
│ ├── gradle.xml
│ ├── compiler.xml
│ └── misc.xml
│ ├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradlew.bat
│ └── gradlew
├── res
├── Android-reviews.png
├── iOS-movies-list.png
├── Android-trailers.png
├── iOS-movie-detail.png
├── Android-movie-detail.png
├── Android-favorite-movies.png
├── Android-popular-movies.png
└── Android-top-rated-movies.png
├── iOS
└── PopularMovies
│ ├── PopularMovies
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── SortingOptions.imageset
│ │ │ ├── SortingOptions.png
│ │ │ ├── SortingOptions@2x.png
│ │ │ ├── SortingOptions@3x.png
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ImagePresentable.swift
│ ├── RealmInt.swift
│ ├── MovieCollectionViewCell.swift
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── MovieDetailViewController.swift
│ ├── MovieDateUtils.swift
│ ├── MovieDetailScrollView.swift
│ ├── MovieRealmManager.swift
│ ├── MovieCellViewModel.swift
│ ├── TMDbConstants.swift
│ ├── MovieCollections.swift
│ ├── Movie.swift
│ ├── AppDelegate.swift
│ ├── MovieDetailViewModel.swift
│ ├── MoviesCollectionViewDataSource.swift
│ ├── TMDbWebservice.swift
│ └── TMDbConfig.swift
│ ├── Podfile
│ ├── Network
│ ├── Network.xcodeproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcuserdata
│ │ │ │ └── ivanmagda.xcuserdatad
│ │ │ │ └── UserInterfaceState.xcuserstate
│ │ └── xcuserdata
│ │ │ └── ivanmagda.xcuserdatad
│ │ │ └── xcschemes
│ │ │ ├── xcschememanagement.plist
│ │ │ └── Network.xcscheme
│ ├── Network
│ │ ├── WebserviceError.swift
│ │ ├── Network.h
│ │ ├── Result.swift
│ │ ├── HttpMethod.swift
│ │ ├── FileStorage.swift
│ │ ├── Cache.swift
│ │ ├── Info.plist
│ │ ├── CachedWebservice.swift
│ │ ├── Webservice.swift
│ │ └── Resource.swift
│ └── NetworkTests
│ │ ├── Info.plist
│ │ └── NetworkTests.swift
│ ├── PopularMovies.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcuserdata
│ │ │ └── ivanmagda.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ └── ivanmagda.xcuserdatad
│ │ ├── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── PopularMovies.xcscheme
│ │ └── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ ├── PopularMovies.xcworkspace
│ └── contents.xcworkspacedata
│ ├── Podfile.lock
│ ├── PopularMoviesTests
│ ├── Info.plist
│ └── PopularMoviesTests.swift
│ └── PopularMoviesUITests
│ ├── Info.plist
│ └── PopularMoviesUITests.swift
├── LICENSE.md
├── README.md
└── .gitignore
/Android/PopularMovies/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Android/PopularMovies/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/res/Android-reviews.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/res/Android-reviews.png
--------------------------------------------------------------------------------
/res/iOS-movies-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/res/iOS-movies-list.png
--------------------------------------------------------------------------------
/res/Android-trailers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/res/Android-trailers.png
--------------------------------------------------------------------------------
/res/iOS-movie-detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/res/iOS-movie-detail.png
--------------------------------------------------------------------------------
/res/Android-movie-detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/res/Android-movie-detail.png
--------------------------------------------------------------------------------
/res/Android-favorite-movies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/res/Android-favorite-movies.png
--------------------------------------------------------------------------------
/res/Android-popular-movies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/res/Android-popular-movies.png
--------------------------------------------------------------------------------
/res/Android-top-rated-movies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/res/Android-top-rated-movies.png
--------------------------------------------------------------------------------
/Android/PopularMovies/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/iOS/PopularMovies/PopularMoviesUITests/PopularMoviesUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PopularMoviesUITests.swift
3 | // PopularMoviesUITests
4 | //
5 | // Created by Ivan Magda on 05/12/2016.
6 | // Copyright © 2016 Ivan Magda. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class PopularMoviesUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | override func tearDown() {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | super.tearDown()
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/iOS/PopularMovies/Network/Network/Webservice.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Webservice.swift
3 | // Videos
4 | //
5 | // Created by Florian on 13/04/16.
6 | // Copyright © 2016 Chris Eidhof. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public typealias JSONDictionary = [String: Any]
12 |
13 | // We create our own session here without a URLCache to avoid playground error messages
14 | private var session: URLSession {
15 | let config = URLSessionConfiguration.default
16 | config.urlCache = nil
17 | return URLSession(configuration: config)
18 | }
19 |
20 | public final class Webservice {
21 | public var authenticationToken: String?
22 | public init() { }
23 |
24 | /// Loads a resource. The completion handler is always called on the main queue.
25 | public func load(_ resource: Resource, completion: @escaping (Result) -> () = logError) {
26 | session.dataTask(with: resource.url, completionHandler: { data, response, _ in
27 | let result: Result
28 | if let httpResponse = response as? HTTPURLResponse , httpResponse.statusCode == 401 {
29 | result = Result.error(WebserviceError.notAuthenticated)
30 | } else {
31 | let parsed = data.flatMap(resource.parse)
32 | result = Result(parsed, or: WebserviceError.other)
33 | }
34 | DispatchQueue.main.async { completion(result) }
35 | }) .resume()
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Android/PopularMovies/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.1"
6 | defaultConfig {
7 | applicationId "com.ivanmagda.popularmovies"
8 | minSdkVersion 15
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 |
28 | compile 'com.android.support:appcompat-v7:25.1.0'
29 | compile 'com.android.support:support-v4:25.1.0'
30 | compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
31 | compile 'com.android.support:recyclerview-v7:25.1.0'
32 | compile 'com.android.support:cardview-v7:25.1.0'
33 |
34 | compile 'com.squareup.picasso:picasso:2.5.2'
35 | compile 'com.jakewharton:butterknife:8.4.0'
36 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
37 |
38 | testCompile 'junit:junit:4.12'
39 | }
40 |
--------------------------------------------------------------------------------
/Android/PopularMovies/app/src/main/res/layout/review_item.xml:
--------------------------------------------------------------------------------
1 |
2 | 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | *
11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ivanmagda.popularmovies;
24 |
25 | /**
26 | * Provide extra constants for Intents.
27 | */
28 | public final class Extras {
29 |
30 | public static final String EXTRA_MOVIE_TRANSFER = "com.ivanmagda.popularmovies.extra_movie_tarnsfer";
31 | public static final String EXTRA_REVIEW_TRANSFER = "com.ivanmagda.popularmovies.extra_review_transfer";
32 | public static final String EXTRA_TRAILER_TRANSFER = "com.ivanmagda.popularmovies.extra_trailer_transfer";
33 |
34 | private Extras() {
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/iOS/PopularMovies/PopularMovies/MovieCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2016 Ivan Magda
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | // MARK: MovieCollectionViewCell: UICollectionViewCell
26 |
27 | final class MovieCollectionViewCell: UICollectionViewCell {
28 |
29 | @IBOutlet weak var posterImageView: UIImageView!
30 |
31 | static let reuseIdentifier = "MovieCell"
32 |
33 | // MARK: Private Variables
34 |
35 | private var delegate: ImagePresentable?
36 |
37 | // MARK: Public
38 |
39 | func configure(with delegate: ImagePresentable) {
40 | posterImageView.image = nil
41 | posterImageView.af_setImage(withURL: delegate.imageUrl)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/data/FavoriteMoviesLoaderCallbacksAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ivanmagda.popularmovies.data;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.support.v4.app.LoaderManager;
8 | import android.support.v4.content.CursorLoader;
9 | import android.support.v4.content.Loader;
10 |
11 | import com.ivanmagda.popularmovies.persistence.MovieContract;
12 |
13 | public final class FavoriteMoviesLoaderCallbacksAdapter implements LoaderManager.LoaderCallbacks
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ivanmagda.popularmovies.view.activity;
24 |
25 | import android.content.Intent;
26 | import android.os.Bundle;
27 | import android.support.v7.app.AppCompatActivity;
28 |
29 | import com.ivanmagda.popularmovies.Extras;
30 | import com.ivanmagda.popularmovies.R;
31 | import com.ivanmagda.popularmovies.data.model.Movie;
32 | import com.ivanmagda.popularmovies.view.fragment.MovieDetailFragment;
33 |
34 | public class MovieDetailActivity extends AppCompatActivity {
35 |
36 | private static final String MOVIE_DETAIL_FRAGMENT_TAG = "movieDetail";
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_movie_detail);
42 |
43 | if (savedInstanceState == null) {
44 | Intent intent = getIntent();
45 | if (intent.hasExtra(Extras.EXTRA_MOVIE_TRANSFER)) {
46 | Movie movie = intent.getParcelableExtra(Extras.EXTRA_MOVIE_TRANSFER);
47 | getSupportFragmentManager()
48 | .beginTransaction()
49 | .add(R.id.activity_movie_detail, MovieDetailFragment.newInstance(movie),
50 | MOVIE_DETAIL_FRAGMENT_TAG)
51 | .commit();
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/view/activity/MoviesListActivity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2016 Ivan Magda
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ivanmagda.popularmovies.view.activity;
24 |
25 | import android.os.Bundle;
26 | import android.support.v7.app.AppCompatActivity;
27 |
28 | import com.ivanmagda.popularmovies.R;
29 | import com.ivanmagda.popularmovies.view.fragment.MoviesListFragment;
30 |
31 | public class MoviesListActivity extends AppCompatActivity {
32 |
33 | private static final String MOVIES_LIST_FRAGMENT_TAG = "moviesListFragment";
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.activity_movies_list);
39 |
40 | if (savedInstanceState == null) {
41 | getSupportFragmentManager()
42 | .beginTransaction()
43 | .add(R.id.activity_movies_list, MoviesListFragment.newInstance(),
44 | MOVIES_LIST_FRAGMENT_TAG)
45 | .commit();
46 | }
47 | }
48 |
49 | @Override
50 | protected void onSaveInstanceState(Bundle outState) {
51 | super.onSaveInstanceState(outState);
52 | android.support.v4.app.FragmentManager manager = getSupportFragmentManager();
53 | manager.putFragment(
54 | outState,
55 | MOVIES_LIST_FRAGMENT_TAG,
56 | manager.findFragmentByTag(MOVIES_LIST_FRAGMENT_TAG));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/utilities/ImageUtils.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2016 Ivan Magda
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ivanmagda.popularmovies.utilities;
24 |
25 | import android.graphics.Bitmap;
26 | import android.graphics.BitmapFactory;
27 | import android.graphics.drawable.BitmapDrawable;
28 | import android.support.annotation.NonNull;
29 | import android.widget.ImageView;
30 |
31 | import java.io.ByteArrayOutputStream;
32 |
33 | public class ImageUtils {
34 |
35 | private ImageUtils() {
36 | }
37 |
38 | /**
39 | * Source code from the post:
40 | * http://stackoverflow.com/questions/37779515/how-can-i-convert-an-imageview-to-byte-array-in-android-studio
41 | *
42 | * @param imageView
43 | * @return byte array
44 | */
45 | public static byte[] bytesFromImageView(@NonNull final ImageView imageView) {
46 | BitmapDrawable bitmapDrawable = (BitmapDrawable) imageView.getDrawable();
47 | if (bitmapDrawable == null) return null;
48 |
49 | Bitmap bitmap = bitmapDrawable.getBitmap();
50 | if (bitmap == null) return null;
51 |
52 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
53 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
54 |
55 | return baos.toByteArray();
56 | }
57 |
58 | public static Bitmap bitmapFromBytes(byte[] data) {
59 | if (data == null || data.length == 0) {
60 | return null;
61 | }
62 | return BitmapFactory.decodeByteArray(data, 0, data.length);
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/iOS/PopularMovies/PopularMovies/MovieCollections.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017 Ivan Magda
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | import Foundation
24 | import RealmSwift
25 |
26 | final class MovieCollections: Object {
27 |
28 | enum MovieTypes: CustomStringConvertible {
29 | case popular, topRated
30 |
31 | var description: String {
32 | switch self {
33 | case .popular:
34 | return "Popular"
35 | case .topRated:
36 | return "Top Rated"
37 | }
38 | }
39 | }
40 |
41 | let popular = List
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ivanmagda.popularmovies.utilities.json;
24 |
25 | import android.text.TextUtils;
26 |
27 | import com.ivanmagda.popularmovies.data.model.Movie;
28 |
29 | import org.json.JSONArray;
30 | import org.json.JSONException;
31 | import org.json.JSONObject;
32 |
33 | import java.util.List;
34 |
35 | /**
36 | * Utility functions to handle TMDb movie JSON data.
37 | */
38 | public final class MovieJsonUtils {
39 |
40 | /* Response keys. */
41 | private static final String RESULTS_RESPONSE_KEY = "results";
42 | private static final String ID_RESPONSE_KEY = "id";
43 | private static final String POSTER_PATH_RESPONSE_KEY = "poster_path";
44 | private static final String OVERVIEW_RESPONSE_KEY = "overview";
45 | private static final String RELEASE_DATE_RESPONSE_KEY = "release_date";
46 | private static final String GENRE_IDS_RESPONSE_KEY = "genre_ids";
47 | private static final String TITLE_RESPONSE_KEY = "original_title";
48 | private static final String VIDEO_RESPONSE_KEY = "video";
49 | private static final String RATING_RESPONSE_KEY = "vote_average";
50 |
51 | private MovieJsonUtils() {
52 | }
53 |
54 | public static List
61 | * Type: INTEGER
62 | */
63 | public static final String COLUMN_MOVIE_ID = "movie_id";
64 |
65 | /**
66 | * Title of the movie.
67 | *
68 | * Type: TEXT
69 | */
70 | public static final String COLUMN_TITLE = "title";
71 |
72 | /**
73 | * Poster of the movie.
74 | *
82 | * Type: TEXT
83 | */
84 | public static final String COLUMN_POSTER_PATH = "poster_path";
85 |
86 | /**
87 | * Rating of the movie.
88 | *
89 | * Type: REAL
90 | */
91 | public static final String COLUMN_RATING = "rating";
92 |
93 | /**
94 | * Release date of the movie.
95 | * Stores as String with format "2016-12-14" - "yyyy-MM-dd".
96 | *
97 | * Type: TEXT
98 | */
99 | public static final String COLUMN_RELEASE_DATE = "date";
100 |
101 | /**
102 | * Synopsis of the movie.
103 | *
104 | * Type: TEXT
105 | */
106 | public static final String COLUMN_OVERVIEW = "overview";
107 |
108 | /**
109 | * Builds a URI that adds the movie id to the end of the movie content URI path.
110 | * This is used to query details about a single movie entry by movie id.
111 | *
112 | * @param movieId Id of the movie in the TMDb.
113 | * @return Uri to query details about a single movie entry
114 | */
115 | public static Uri buildFavoriteMovieUriWithId(int movieId) {
116 | return ContentUris.withAppendedId(CONTENT_URI, movieId);
117 | }
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------
/Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/data/model/Movie.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2016 Ivan Magda
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ivanmagda.popularmovies.data.model;
24 |
25 | import android.os.Parcel;
26 | import android.os.Parcelable;
27 |
28 | import com.ivanmagda.popularmovies.utilities.MovieDateUtils;
29 |
30 | import java.util.Date;
31 |
32 | /**
33 | * Defines TMDb movie object.
34 | */
35 | public final class Movie implements Parcelable {
36 |
37 | private final int mId;
38 | private final String mPosterPath;
39 | private final String mOverview;
40 | private final String mReleaseDateString;
41 | private final String mTitle;
42 | private final double mRating;
43 | private byte[] mPoster;
44 |
45 | public Movie(int id, String posterPath, String overview, String releaseDateString, String title,
46 | double rating, byte[] poster) {
47 | this.mId = id;
48 | this.mPosterPath = posterPath;
49 | this.mOverview = overview;
50 | this.mReleaseDateString = releaseDateString;
51 | this.mTitle = title;
52 | this.mRating = rating;
53 | this.mPoster = poster;
54 | }
55 |
56 | public Movie(Parcel in) {
57 | this.mId = in.readInt();
58 | this.mPosterPath = in.readString();
59 | this.mOverview = in.readString();
60 | this.mReleaseDateString = in.readString();
61 | this.mTitle = in.readString();
62 | this.mRating = in.readDouble();
63 | }
64 |
65 | @Override
66 | public int describeContents() {
67 | return 0;
68 | }
69 |
70 | @Override
71 | public void writeToParcel(Parcel dest, int i) {
72 | dest.writeInt(mId);
73 | dest.writeString(mPosterPath);
74 | dest.writeString(mOverview);
75 | dest.writeString(mReleaseDateString);
76 | dest.writeString(mTitle);
77 | dest.writeDouble(mRating);
78 | }
79 |
80 | public static final Parcelable.Creator
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ivanmagda.popularmovies.network;
24 |
25 | import android.util.Log;
26 |
27 | import java.io.BufferedReader;
28 | import java.io.IOException;
29 | import java.io.InputStream;
30 | import java.io.InputStreamReader;
31 | import java.net.HttpURLConnection;
32 | import java.net.URL;
33 |
34 | /**
35 | * Provide an abstraction over the webservice.
36 | * Does loading data over the network.
37 | */
38 | public final class Webservice {
39 |
40 | /* Log tag for debug statements. */
41 | private static String LOG_TAG = Webservice.class.getSimpleName();
42 |
43 | private Webservice() {
44 | }
45 |
46 | /**
47 | * @param resource The resourse to be loaded using HttpUrlConnection.
48 | * @param The generic return parameter, that will return resourse.parseBlock.parse function.
49 | * @return Result after parsing.
50 | */
51 | public static A load(Resource resource) {
52 | // Getting a connection to the resource referred to by this URL
53 | // and trying to connect.
54 | HttpURLConnection connection = null;
55 | URL url = resource.url;
56 |
57 | if (url == null) {
58 | return null;
59 | }
60 |
61 | try {
62 | connection = (HttpURLConnection) url.openConnection();
63 | connection.setReadTimeout(10000);
64 | connection.setConnectTimeout(15000);
65 | connection.setRequestMethod(resource.httpMethodName);
66 | connection.setDoInput(true);
67 | connection.connect();
68 |
69 | String response = processOnResponse(connection);
70 |
71 | return resource.parseBlock.parse(response);
72 | } catch (IOException exception) {
73 | Log.e(LOG_TAG, "Failed to download raw data", exception);
74 | } finally {
75 | if (connection != null) {
76 | connection.disconnect();
77 | }
78 | }
79 |
80 | return null;
81 | }
82 |
83 | private static String processOnResponse(HttpURLConnection connection) {
84 | try {
85 | // Did we receive a successful 2XX status code.
86 | int responseCode = connection.getResponseCode();
87 | if (responseCode < HttpURLConnection.HTTP_OK || responseCode > 299) {
88 | Log.w(LOG_TAG, "Received status code other then 2XX, status code: " + responseCode);
89 | return null;
90 | }
91 | Log.d(LOG_TAG, "Response status code: " + responseCode
92 | + " for URL: " + connection.getURL());
93 | return readInputs(connection.getInputStream());
94 | } catch (IOException exception) {
95 | Log.e(LOG_TAG, "Failed to process on http response", exception);
96 | }
97 |
98 | return null;
99 | }
100 |
101 | private static String readInputs(InputStream inputStream) throws IOException {
102 | if (inputStream == null) {
103 | return null;
104 | }
105 |
106 | StringBuilder stringBuilder = new StringBuilder();
107 | BufferedReader reader = new BufferedReader((new InputStreamReader(inputStream)));
108 |
109 | // Reading each line of the data.
110 | String line;
111 | while ((line = reader.readLine()) != null) {
112 | stringBuilder.append(line).append("\n");
113 | }
114 |
115 | reader.close();
116 | inputStream.close();
117 |
118 | return stringBuilder.toString();
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/data/MovieAdapter.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2016 Ivan Magda
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | package com.ivanmagda.popularmovies.data;
24 |
25 | import android.content.Context;
26 | import android.support.annotation.NonNull;
27 | import android.view.LayoutInflater;
28 | import android.view.View;
29 | import android.view.ViewGroup;
30 | import android.widget.ArrayAdapter;
31 | import android.widget.ImageView;
32 |
33 | import com.ivanmagda.popularmovies.R;
34 | import com.ivanmagda.popularmovies.data.model.Movie;
35 | import com.ivanmagda.popularmovies.network.tmdb.TMDbApi;
36 | import com.squareup.picasso.Picasso;
37 |
38 | import java.net.URL;
39 | import java.util.ArrayList;
40 | import java.util.List;
41 |
42 | import butterknife.BindView;
43 | import butterknife.ButterKnife;
44 |
45 | public final class MovieAdapter extends ArrayAdapter
12 |
17 |
22 |
27 |