├── 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 | 2 | 3 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Android/PopularMovies/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/Android/PopularMovies/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/Android/PopularMovies/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/Android/PopularMovies/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/PopularMovies/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/Android/PopularMovies/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/Android/PopularMovies/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/Android/PopularMovies/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/dictionaries/ivanmagda.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | chappie 5 | 6 | 7 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '8.0' 2 | 3 | target 'PopularMovies' do 4 | use_frameworks! 5 | inhibit_all_warnings! 6 | 7 | pod 'AlamofireImage', '3.2.0' 8 | pod 'RealmSwift', '2.2' 9 | end 10 | -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies/Assets.xcassets/SortingOptions.imageset/SortingOptions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/iOS/PopularMovies/PopularMovies/Assets.xcassets/SortingOptions.imageset/SortingOptions.png -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies/Assets.xcassets/SortingOptions.imageset/SortingOptions@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/iOS/PopularMovies/PopularMovies/Assets.xcassets/SortingOptions.imageset/SortingOptions@2x.png -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies/Assets.xcassets/SortingOptions.imageset/SortingOptions@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/iOS/PopularMovies/PopularMovies/Assets.xcassets/SortingOptions.imageset/SortingOptions@3x.png -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies.xcodeproj/project.xcworkspace/xcuserdata/ivanmagda.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/iOS/PopularMovies/PopularMovies.xcodeproj/project.xcworkspace/xcuserdata/ivanmagda.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network.xcodeproj/project.xcworkspace/xcuserdata/ivanmagda.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivan-magda/Popular-Movies/HEAD/iOS/PopularMovies/Network/Network.xcodeproj/project.xcworkspace/xcuserdata/ivanmagda.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Android/PopularMovies/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/menu/detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/layout/activity_movie_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/layout/activity_movies_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network/WebserviceError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WebserviceError.swift 3 | // Videos 4 | // 5 | // Created by Florian on 13/04/16. 6 | // Copyright © 2016 Chris Eidhof. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum WebserviceError: Error { 12 | case notAuthenticated 13 | case other 14 | } 15 | 16 | func logError(_ result: Result) { 17 | guard case let .error(e) = result else { return } 18 | assert(false, "\(e)") 19 | } 20 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/layout/fragment_movies_list.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #212121 4 | #000000 5 | #9E9E9E 6 | #359787 7 | #BDBDBD 8 | 9 | #212121 10 | #757575 11 | 12 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/test/java/com/ivanmagda/popularmovies/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.ivanmagda.popularmovies; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies/Assets.xcassets/SortingOptions.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "SortingOptions.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "SortingOptions@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "SortingOptions@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/layout/movie_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network/Network.h: -------------------------------------------------------------------------------- 1 | // 2 | // Network.h 3 | // Network 4 | // 5 | // Created by Ivan Magda on 28/11/2016. 6 | // Copyright © 2016 Ivan Magda. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Network. 12 | FOUNDATION_EXPORT double NetworkVersionNumber; 13 | 14 | //! Project version string for Network. 15 | FOUNDATION_EXPORT const unsigned char NetworkVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Android/PopularMovies/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 15 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/layout/activity_reviews.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network/Result.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Result.swift 3 | // Videos 4 | // 5 | // Created by Florian on 13/04/16. 6 | // Copyright © 2016 Chris Eidhof. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum Result { 12 | case success(A) 13 | case error(Error) 14 | } 15 | 16 | extension Result { 17 | public init(_ value: A?, or error: Error) { 18 | if let value = value { 19 | self = .success(value) 20 | } else { 21 | self = .error(error) 22 | } 23 | } 24 | 25 | public var value: A? { 26 | guard case .success(let v) = self else { return nil } 27 | return v 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (4.3.0) 3 | - AlamofireImage (3.2.0): 4 | - Alamofire (~> 4.1) 5 | - Realm (2.2.0): 6 | - Realm/Headers (= 2.2.0) 7 | - Realm/Headers (2.2.0) 8 | - RealmSwift (2.2.0): 9 | - Realm (= 2.2.0) 10 | 11 | DEPENDENCIES: 12 | - AlamofireImage (= 3.2.0) 13 | - RealmSwift (= 2.2) 14 | 15 | SPEC CHECKSUMS: 16 | Alamofire: 856a113053a7bc9cbe5d6367a555d773fc5cfef7 17 | AlamofireImage: 157ed682cc81d3b9db4fb90c1f12180ac552d93b 18 | Realm: d95b8fb34c83f1e764b66d319277a62c2b6e4bf5 19 | RealmSwift: a4fa52d06e946a32ec746b3388374f742e6b8731 20 | 21 | PODFILE CHECKSUM: 3d414ca61a0ad47422d5ca9d4344ba7814e198e1 22 | 23 | COCOAPODS: 1.1.1 24 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/layout/activity_trailers.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | 16dp 7 | 16dp 8 | 9 | 150dp 10 | 300dp 11 | 12 | 32dp 13 | 250dp 14 | 4dp 15 | 4dp 16 | 17 | -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network/HttpMethod.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HttpMethod.swift 3 | // Videos 4 | // 5 | // Created by Florian on 13/04/16. 6 | // Copyright © 2016 Chris Eidhof. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public enum HttpMethod { 12 | case get 13 | case post(data: A) 14 | 15 | public var method: String { 16 | switch self { 17 | case .get: return "GET" 18 | case .post: return "POST" 19 | } 20 | } 21 | 22 | public func map(f: (A) throws -> B) rethrows -> HttpMethod { 23 | switch self { 24 | case .get: return .get 25 | case .post(let data): return .post(data: try f(data)) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/utilities/ConnectivityUtils.java: -------------------------------------------------------------------------------- 1 | package com.ivanmagda.popularmovies.utilities; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | public final class ConnectivityUtils { 8 | 9 | private ConnectivityUtils() { 10 | } 11 | 12 | public static boolean isOnline(Context context) { 13 | ConnectivityManager connectivityManager = (ConnectivityManager) 14 | context.getSystemService(Context.CONNECTIVITY_SERVICE); 15 | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); 16 | return networkInfo != null && networkInfo.isConnected(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network/FileStorage.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 Foundation 10 | 11 | struct FileStorage { 12 | let baseURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) 13 | 14 | subscript(key: String) -> Data? { 15 | get { 16 | let url = baseURL.appendingPathComponent(key) 17 | return try? Data(contentsOf: url) 18 | } 19 | set { 20 | let url = baseURL.appendingPathComponent(key) 21 | _ = try? newValue?.write(to: url) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Android/PopularMovies/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 /Users/ivanmagda/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network.xcodeproj/xcuserdata/ivanmagda.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Network.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 7550EF591DEBD1D00006E458 16 | 17 | primary 18 | 19 | 20 | 7550EF621DEBD1D00006E458 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMoviesTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/NetworkTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMoviesUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Android/PopularMovies/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/layout/trailer_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network/Cache.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 Foundation 10 | 11 | extension Resource { 12 | var cacheKey: String { 13 | return "cache" + String(url.hashValue) 14 | } 15 | } 16 | 17 | final class Cache { 18 | var storage = FileStorage() 19 | 20 | func load(_ resource: Resource) -> A? { 21 | guard case .get = resource.method else { return nil } 22 | let data = storage[resource.cacheKey] 23 | return data.flatMap(resource.parse) 24 | } 25 | 26 | func save(_ data: Data, for resource: Resource) { 27 | guard case .get = resource.method else { return } 28 | storage[resource.cacheKey] = data 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Android/PopularMovies/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies.xcodeproj/xcuserdata/ivanmagda.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PopularMovies.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 7500A1231DF57CAD00B17251 16 | 17 | primary 18 | 19 | 20 | 7500A1371DF57CAE00B17251 21 | 22 | primary 23 | 24 | 25 | 7500A1421DF57CAE00B17251 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/network/MoviesLoader.java: -------------------------------------------------------------------------------- 1 | package com.ivanmagda.popularmovies.network; 2 | 3 | import android.content.Context; 4 | import android.support.v4.content.AsyncTaskLoader; 5 | 6 | import com.ivanmagda.popularmovies.data.model.Movie; 7 | 8 | import java.util.List; 9 | 10 | public final class MoviesLoader extends AsyncTaskLoader> { 11 | 12 | private Resource> mResource; 13 | 14 | public MoviesLoader(Context context, Resource> resource) { 15 | super(context); 16 | this.mResource = resource; 17 | } 18 | 19 | @Override 20 | protected void onStartLoading() { 21 | forceLoad(); 22 | } 23 | 24 | @Override 25 | public List loadInBackground() { 26 | if (mResource == null) { 27 | return null; 28 | } 29 | return Webservice.load(mResource); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/androidTest/java/com/ivanmagda/popularmovies/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.ivanmagda.popularmovies; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.ivanmagda.popularmovies", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies.xcodeproj/xcuserdata/ivanmagda.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/utilities/json/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.ivanmagda.popularmovies.utilities.json; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONException; 5 | import org.json.JSONObject; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public final class JsonUtils { 11 | 12 | interface Parcelable { 13 | T parse(JSONObject jsonObject) throws JSONException; 14 | } 15 | 16 | private JsonUtils() { 17 | } 18 | 19 | public static List parseJsonArray(JSONArray jsonArray, Parcelable parcelable) 20 | throws JSONException { 21 | ArrayList parsedArray = new ArrayList<>(jsonArray.length()); 22 | 23 | for (int i = 0; i < jsonArray.length(); i++) { 24 | JSONObject jsonObject = jsonArray.getJSONObject(i); 25 | T parsed = parcelable.parse(jsonObject); 26 | if (parsed != null) { 27 | parsedArray.add(parsed); 28 | } 29 | } 30 | 31 | return parsedArray; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 Ivan Magda 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/NetworkTests/NetworkTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkTests.swift 3 | // NetworkTests 4 | // 5 | // Created by Ivan Magda on 28/11/2016. 6 | // Copyright © 2016 Ivan Magda. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Network 11 | 12 | class NetworkTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMoviesTests/PopularMoviesTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopularMoviesTests.swift 3 | // PopularMoviesTests 4 | // 5 | // Created by Ivan Magda on 05/12/2016. 6 | // Copyright © 2016 Ivan Magda. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import PopularMovies 11 | 12 | class PopularMoviesTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /iOS/PopularMovies/Network/Network/CachedWebservice.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 Foundation 10 | 11 | public final class CachedWebservice { 12 | let webservice: Webservice 13 | let cache = Cache() 14 | 15 | public init() { 16 | self.webservice = Webservice() 17 | } 18 | 19 | public init(_ webservice: Webservice) { 20 | self.webservice = webservice 21 | } 22 | 23 | public func load(_ resource: Resource, update: @escaping (Result) -> ()) { 24 | if let result = cache.load(resource) { 25 | print("Cache hit") 26 | update(.success(result)) 27 | } 28 | 29 | let dataResource = Resource(url: resource.url, parse: { $0 }, method: resource.method) 30 | webservice.load(dataResource, completion: { result in 31 | switch result { 32 | case let .error(error): 33 | update(.error(error)) 34 | case let .success(data): 35 | self.cache.save(data, for: resource) 36 | update(Result(resource.parse(data), or: WebserviceError.other)) 37 | } 38 | }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies/ImagePresentable.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 Foundation 24 | 25 | protocol ImagePresentable { 26 | var imageUrl: URL { get } 27 | } 28 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies/RealmInt.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 RealmInt: Object { 27 | dynamic var value = 0 28 | } 29 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/data/FavoriteMoviesAdapter.java: -------------------------------------------------------------------------------- 1 | package com.ivanmagda.popularmovies.data; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.CursorAdapter; 9 | import android.widget.ImageView; 10 | 11 | import com.ivanmagda.popularmovies.R; 12 | import com.ivanmagda.popularmovies.data.model.Movie; 13 | import com.ivanmagda.popularmovies.utilities.ImageUtils; 14 | import com.ivanmagda.popularmovies.utilities.MoviePersistenceUtils; 15 | 16 | public final class FavoriteMoviesAdapter extends CursorAdapter { 17 | 18 | public FavoriteMoviesAdapter(Context context, Cursor cursor) { 19 | super(context, cursor, 0); 20 | } 21 | 22 | @Override 23 | public View newView(Context context, Cursor cursor, ViewGroup parent) { 24 | return LayoutInflater.from(context).inflate(R.layout.movie_item, parent, false); 25 | } 26 | 27 | @Override 28 | public void bindView(View view, Context context, Cursor cursor) { 29 | Movie movie = MoviePersistenceUtils.makeFromCursor(cursor); 30 | 31 | ImageView imageView = (ImageView) view.findViewById(R.id.iv_item_movie_poster); 32 | imageView.setImageBitmap(ImageUtils.bitmapFromBytes(movie.getPoster())); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PopularMovies 2 | 3 | [![codebeat badge](https://codebeat.co/badges/3311300e-7131-4915-957b-d77f7a87b884)](https://codebeat.co/projects/github-com-vanyaland-popular-movies-master) 4 | 5 | ## Description 6 | This application help users discover popular and recent movies using [TMDb API](https://www.themoviedb.org/documentation/api). 7 | 8 | ### Android Installation 9 | - Obtain an [TMDb API](https://www.themoviedb.org/documentation/api) Key. 10 | - In `TMDbApi.java`, replace `API_KEY` constant with your own. 11 | - Build & run, enjoy. 12 | 13 | 14 | ### iOS Installation 15 | - Obtain an [TMDb API](https://www.themoviedb.org/documentation/api) Key. 16 | - Run `pod install` on iOS project root directory `.../PopularMovies/iOS/PopularMovies` ([CocoaPods Installation](https://guides.cocoapods.org/using/getting-started.html)). 17 | - Open `PopularMovies.xcworkspace` and build. 18 | - In `TMDbConstants.swift`, replace `apiKey` with your own in the `TMDbConstants.TMDBParameterValues` struct. 19 | - Build & run, enjoy. 20 | 21 | ## Screenshots 22 | 23 | 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 | 11 | 12 | 16 | 17 | 23 | 24 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/network/tmdb/ReviewsFetchTask.java: -------------------------------------------------------------------------------- 1 | package com.ivanmagda.popularmovies.network.tmdb; 2 | 3 | import android.os.AsyncTask; 4 | import android.support.annotation.NonNull; 5 | 6 | import com.ivanmagda.popularmovies.data.model.Movie; 7 | import com.ivanmagda.popularmovies.data.model.Review; 8 | import com.ivanmagda.popularmovies.network.Webservice; 9 | 10 | import java.util.List; 11 | 12 | public final class ReviewsFetchTask extends AsyncTask> { 13 | 14 | public interface CompletionHandler { 15 | void block(List reviews); 16 | } 17 | 18 | private Movie mMovie; 19 | private CompletionHandler mCompletionHandler; 20 | 21 | public ReviewsFetchTask(@NonNull final Movie movie, CompletionHandler completionHandler) { 22 | this.mMovie = movie; 23 | this.mCompletionHandler = completionHandler; 24 | } 25 | 26 | public static void load(@NonNull final Movie movie, CompletionHandler completionHandler) { 27 | new ReviewsFetchTask(movie, completionHandler).execute(); 28 | } 29 | 30 | @Override 31 | protected List doInBackground(Void... params) { 32 | return Webservice.load(TMDbApi.getReviewsForMovie(mMovie)); 33 | } 34 | 35 | @Override 36 | protected void onPostExecute(List reviews) { 37 | if (mCompletionHandler != null) { 38 | mCompletionHandler.block(reviews); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/network/tmdb/TrailersFetchTask.java: -------------------------------------------------------------------------------- 1 | package com.ivanmagda.popularmovies.network.tmdb; 2 | 3 | import android.os.AsyncTask; 4 | import android.support.annotation.NonNull; 5 | 6 | import com.ivanmagda.popularmovies.data.model.Movie; 7 | import com.ivanmagda.popularmovies.data.model.YouTubeTrailer; 8 | import com.ivanmagda.popularmovies.network.Webservice; 9 | 10 | import java.util.List; 11 | 12 | public final class TrailersFetchTask extends AsyncTask> { 13 | 14 | public interface CompletionHandler { 15 | void block(List trailers); 16 | } 17 | 18 | private Movie mMovie; 19 | private CompletionHandler mCompletionHandler; 20 | 21 | public TrailersFetchTask(@NonNull final Movie movie, CompletionHandler completionHandler) { 22 | this.mMovie = movie; 23 | this.mCompletionHandler = completionHandler; 24 | } 25 | 26 | public static void load(@NonNull final Movie movie, CompletionHandler completionHandler) { 27 | new TrailersFetchTask(movie, completionHandler).execute(); 28 | } 29 | 30 | @Override 31 | protected List doInBackground(Void... params) { 32 | return Webservice.load(TMDbApi.getVideosForMovie(mMovie)); 33 | } 34 | 35 | @Override 36 | protected void onPostExecute(List youTubeTrailers) { 37 | if (mCompletionHandler != null) { 38 | mCompletionHandler.block(youTubeTrailers); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/utilities/YouTubeTrailerUtils.java: -------------------------------------------------------------------------------- 1 | package com.ivanmagda.popularmovies.utilities; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.net.Uri; 6 | import android.support.annotation.NonNull; 7 | 8 | import com.ivanmagda.popularmovies.data.model.YouTubeTrailer; 9 | 10 | public final class YouTubeTrailerUtils { 11 | 12 | private YouTubeTrailerUtils() { 13 | } 14 | 15 | public static void openVideoInWeb(@NonNull final Context context, 16 | @NonNull final YouTubeTrailer trailer) { 17 | Intent playTrailerIntent = new Intent(Intent.ACTION_VIEW); 18 | Uri uri = YouTubeTrailerUtils.buildVideoUriForTrailer(trailer); 19 | playTrailerIntent.setData(uri); 20 | context.startActivity(playTrailerIntent); 21 | } 22 | 23 | public static Uri buildVideoThumbnailUriForTrailer(YouTubeTrailer trailer) { 24 | return buildVideoThumbnailUriWithId(trailer.getKey()); 25 | } 26 | 27 | public static Uri buildVideoThumbnailUriWithId(String videoId) { 28 | return Uri.parse("http://img.youtube.com/vi/" + videoId + "/0.jpg"); 29 | } 30 | 31 | public static Uri buildVideoUriForTrailer(@NonNull final YouTubeTrailer trailer) { 32 | return buildVideoUriWithId(trailer.getKey()); 33 | } 34 | 35 | public static Uri buildVideoUriWithId(@NonNull final String videoId) { 36 | return Uri.parse("https://www.youtube.com/watch?v=" + videoId); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Popular Movies 4 | Detail 5 | 6 | 7 | Most Popular 8 | Top Rated 9 | "Rating: " 10 | "Release year: " 11 | 12 | Popular Movies 13 | Top Rated 14 | 15 | Mark as favorite 16 | Remove from favorites 17 | Favorite 18 | Favorite Movies 19 | There is no internet connection 20 | Reviews 21 | Overview 22 | More 23 | No reviews. 24 | Reviews 25 | Trailers 26 | No trailers. 27 | Trailers 28 | Share 29 | 30 | 31 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/java/com/ivanmagda/popularmovies/Extras.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; 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 { 14 | 15 | public interface Delegate { 16 | public void didFinishLoading(FavoriteMoviesLoaderCallbacksAdapter callbacksAdapter, Cursor cursor); 17 | 18 | public void didLoadReset(FavoriteMoviesLoaderCallbacksAdapter callbacksAdapter); 19 | } 20 | 21 | private Context mContext; 22 | private Delegate mDelegate; 23 | 24 | public FavoriteMoviesLoaderCallbacksAdapter(Context context, Delegate delegate) { 25 | this.mContext = context; 26 | this.mDelegate = delegate; 27 | } 28 | 29 | @Override 30 | public Loader onCreateLoader(int id, Bundle args) { 31 | Uri uri = MovieContract.MovieEntry.CONTENT_URI; 32 | String sortOrder = MovieContract.MovieEntry.COLUMN_RATING + " DESC"; 33 | return new CursorLoader(mContext, uri, null, null, null, sortOrder); 34 | } 35 | 36 | @Override 37 | public void onLoadFinished(Loader loader, Cursor cursor) { 38 | if (mDelegate != null) { 39 | mDelegate.didFinishLoading(this, cursor); 40 | } 41 | } 42 | 43 | @Override 44 | public void onLoaderReset(Loader cursor) { 45 | if (mDelegate != null) { 46 | mDelegate.didLoadReset(this); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /iOS/PopularMovies/PopularMovies/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Android/PopularMovies/app/src/main/res/layout/review.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 18 | 19 | 26 | 27 | 34 | 35 | 36 |