├── .github
├── FUNDING.yml
└── workflows
│ ├── android-ci.yml
│ └── detekt-analysis.yml
├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── frogoboxmedia.jks
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── frogobox
│ │ └── movie
│ │ ├── mvvm
│ │ ├── favorite
│ │ │ ├── FavoriteFragment.kt
│ │ │ ├── FavoriteMovieFragment.kt
│ │ │ ├── FavoriteMovieViewModel.kt
│ │ │ ├── FavoriteTvShowFragment.kt
│ │ │ └── FavoriteTvShowViewModel.kt
│ │ ├── main
│ │ │ ├── MainActivity.kt
│ │ │ ├── MainActivityViewModel.kt
│ │ │ ├── MainViewModel.kt
│ │ │ ├── SettingActivity.kt
│ │ │ └── SettingViewModel.kt
│ │ ├── movie
│ │ │ ├── DetailMovieActivity.kt
│ │ │ ├── DetailMovieViewModel.kt
│ │ │ ├── MovieFragment.kt
│ │ │ ├── SearchMovieActivity.kt
│ │ │ └── SearchMovieViewModel.kt
│ │ └── tv
│ │ │ ├── DetailTvShowActivity.kt
│ │ │ ├── DetailTvShowViewModel.kt
│ │ │ ├── SearchTvShowActivity.kt
│ │ │ ├── SearchTvShowViewModel.kt
│ │ │ └── TvShowFragment.kt
│ │ ├── provider
│ │ ├── FavoriteMovieProvider.kt
│ │ └── FavoriteTvShowProvider.kt
│ │ ├── util
│ │ ├── BaseAppActivity.kt
│ │ └── ViewModelFactory.kt
│ │ └── widget
│ │ ├── FavoriteBannerWidget.kt
│ │ ├── StackRemoteViewFactory.kt
│ │ └── StackWidgetService.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── ic_launcher.xml
│ └── ic_launcher_background.xml
│ ├── layout
│ ├── activity_main.xml
│ ├── activity_search.xml
│ ├── activity_setting.xml
│ ├── fragment_favorite.xml
│ ├── fragment_tv_movie_grid.xml
│ ├── fragment_tv_movie_list.xml
│ ├── toolbar_search.xml
│ ├── widget_banner_favorite.xml
│ └── widget_content_item.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ └── favorite_banner_widget_info.xml
├── base
├── .gitignore
├── build.gradle.kts
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── frogobox
│ │ └── base
│ │ ├── BaseActivity.kt
│ │ ├── BaseApiModel.kt
│ │ ├── BaseApplication.kt
│ │ ├── BaseCallback.kt
│ │ ├── BaseDataSource.kt
│ │ ├── BaseFragment.kt
│ │ ├── BaseHelper.kt
│ │ ├── BaseListener.kt
│ │ ├── BaseViewAdapter.kt
│ │ ├── BaseViewHolder.kt
│ │ ├── BaseViewModel.kt
│ │ ├── adapter
│ │ ├── FavoriteMovieAdapter.kt
│ │ ├── FavoriteTvShowAdapter.kt
│ │ ├── MovieAdapter.kt
│ │ └── TvShowAdapter.kt
│ │ ├── callback
│ │ ├── DeleteViewCallback.kt
│ │ └── SaveViewCallback.kt
│ │ ├── service
│ │ ├── AlarmReceiver.kt
│ │ └── Notification.kt
│ │ ├── source
│ │ ├── DataSource.kt
│ │ ├── Repository.kt
│ │ ├── local
│ │ │ ├── AppDatabase.kt
│ │ │ ├── LocalDataSource.kt
│ │ │ └── dao
│ │ │ │ ├── FavoriteMovieDao.kt
│ │ │ │ └── FavoriteTvShowDao.kt
│ │ ├── model
│ │ │ ├── FavoriteMovie.kt
│ │ │ ├── FavoriteTvShow.kt
│ │ │ ├── Movie.kt
│ │ │ └── TvShow.kt
│ │ └── remote
│ │ │ ├── ApiCallback.kt
│ │ │ ├── ApiService.kt
│ │ │ └── RemoteDataSource.kt
│ │ └── util
│ │ ├── AppExecutors.kt
│ │ ├── Constant.kt
│ │ ├── DiskIOThreadExecutor.kt
│ │ ├── Helper.kt
│ │ ├── Injection.kt
│ │ ├── NullAdapter.kt
│ │ ├── PagerHelper.kt
│ │ └── SingleLiveEvent.kt
│ └── res
│ ├── drawable
│ ├── background_card.xml
│ ├── ic_arrow_back.xml
│ ├── ic_close.xml
│ ├── ic_favorite.xml
│ ├── ic_movie.xml
│ ├── ic_notification.xml
│ ├── ic_search.xml
│ ├── ic_settings.xml
│ ├── ic_translate.xml
│ ├── ic_tv.xml
│ └── ic_un_favorite.xml
│ ├── layout
│ ├── activity_detail.xml
│ ├── empty_view.xml
│ ├── item_grid_tv_movie.xml
│ └── item_list_tv_movie.xml
│ ├── menu
│ ├── bottom_nav.xml
│ ├── toolbar_favorite.xml
│ └── toolbar_main.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ └── strings.xml
├── build.gradle.kts
├── buildSrc
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── AdmobValue.kt
│ ├── BuildConstant.kt
│ ├── DependencyGradle.kt
│ └── ProjectSetting.kt
├── docs
└── image
│ ├── mad_score.png
│ ├── ss_1.png
│ ├── ss_2.png
│ ├── ss_3.png
│ ├── ss_banner.png
│ └── ss_play_store.jpg
├── favorite
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── frogobox
│ │ └── favorite
│ │ ├── mvvm
│ │ ├── main
│ │ │ └── MainActivity.kt
│ │ ├── movie
│ │ │ ├── DetailMovieActivity.kt
│ │ │ ├── DetailMovieViewModel.kt
│ │ │ ├── MovieFragment.kt
│ │ │ └── MovieViewModel.kt
│ │ └── tv
│ │ │ ├── DetailTvShowActivity.kt
│ │ │ ├── DetailTvShowViewModel.kt
│ │ │ ├── TvShowFragment.kt
│ │ │ └── TvShowViewModel.kt
│ │ └── util
│ │ ├── BaseFavoriteActivity.kt
│ │ └── ViewModelFactory.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ ├── activity_main.xml
│ └── fragment_tv_movie_list.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: https://saweria.co/amirisback
13 |
--------------------------------------------------------------------------------
/.github/workflows/android-ci.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | env:
4 | # The name of the main module repository
5 | main_project_module: app
6 |
7 | # The name of the Play Store
8 | playstore_name: Frogobox ID
9 |
10 | on:
11 | # Triggers the workflow on push or pull request events but only for default and protected branches
12 | push:
13 | branches: [ master ]
14 | pull_request:
15 | branches: [ master ]
16 |
17 | workflow_dispatch:
18 | # The workflow will be dispatched to the default queue
19 | branches: [ master ]
20 |
21 | jobs:
22 | build:
23 |
24 | runs-on: ubuntu-latest
25 |
26 | steps:
27 | - uses: actions/checkout@v1
28 |
29 | # Set Current Date As Env Variable
30 | - name: Set current date as env variable
31 | run: echo "date_today=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
32 |
33 | # Set Repository Name As Env Variable
34 | - name: Set repository name as env variable
35 | run: echo "repository_name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV
36 |
37 | - name: Set Up JDK
38 | uses: actions/setup-java@v1
39 | with:
40 | java-version: 11
41 |
42 | - name: Change wrapper permissions
43 | run: chmod +x ./gradlew
44 |
45 | # Run Tests Build
46 | - name: Run gradle tests
47 | run: ./gradlew test
48 |
49 | # Run Build Project
50 | - name: Build gradle project
51 | run: ./gradlew build
52 |
53 | # Create APK Debug
54 | - name: Build apk debug project (APK) - ${{ env.main_project_module }} module
55 | run: ./gradlew assembleDebug
56 |
57 | # Create APK Release
58 | - name: Build apk release project (APK) - ${{ env.main_project_module }} module
59 | run: ./gradlew assemble
60 |
61 | # Create Bundle AAB Release
62 | # Noted for main module build [main_project_module]:bundleRelease
63 | - name: Build app bundle release (AAB) - ${{ env.main_project_module }} module
64 | run: ./gradlew ${{ env.main_project_module }}:bundleRelease
65 |
66 | # Upload Artifact Build
67 | # Noted For Output [main_project_module]/build/outputs/bundle/release/
68 | - name: Upload AAB (App Bundle) Release - ${{ env.repository_name }}
69 | uses: actions/upload-artifact@v2
70 | with:
71 | name: ${{ env.date_today }} - ${{ env.playstore_name }} - ${{ env.repository_name }} - App bundle(s) AAB release generated
72 | path: ${{ env.main_project_module }}/build/outputs/bundle/release/
73 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /.gradle
3 | .gradle
4 | .idea
5 | /local.properties
6 | /.idea/libraries
7 | /.idea/modules.xml
8 | /.idea/workspace.xml
9 | .DS_Store
10 | build
11 | /build
12 | /captures
13 | .externalNativeBuild
14 |
15 | built application files
16 | .apk
17 | .ap_
18 |
19 | files for the dex VM
20 | *.dex
21 |
22 | Java class files
23 | *.class
24 |
25 | generated files
26 | bin/
27 | gen/
28 | .externalNativeBuild/
29 |
30 | Local configuration file (sdk path, etc)
31 | local.properties
32 | app/version.properties
33 |
34 | # SonarQube
35 | .sonar/
36 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/frogoboxmedia.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/frogoboxmedia.jks
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
11 |
14 |
17 |
18 |
26 |
27 |
30 |
33 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
52 |
55 |
56 |
57 |
60 |
61 |
65 |
66 |
72 |
73 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/favorite/FavoriteFragment.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.favorite
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import com.frogobox.base.BaseFragment
7 | import com.frogobox.base.util.PagerHelper
8 |
9 | import com.frogobox.movie.R
10 | import com.frogobox.movie.databinding.FragmentFavoriteBinding
11 |
12 | class FavoriteFragment : BaseFragment() {
13 |
14 | override fun setupViewBinding(
15 | inflater: LayoutInflater,
16 | container: ViewGroup
17 | ): FragmentFavoriteBinding {
18 | return FragmentFavoriteBinding.inflate(inflater, container, false)
19 | }
20 |
21 | override fun setupViewModel() {
22 | }
23 |
24 | override fun setupUI(savedInstanceState: Bundle?) {
25 | mActivity.title = getString(R.string.title_favorite)
26 | setupViewPager()
27 | }
28 |
29 | private fun setupViewPager(){
30 | val pagerAdapter = PagerHelper(childFragmentManager)
31 | pagerAdapter.setupPagerFragment(FavoriteMovieFragment(), resources.getString(R.string.title_favorite_movie))
32 | pagerAdapter.setupPagerFragment(FavoriteTvShowFragment(), resources.getString(R.string.title_favorite_tv_show))
33 | binding?.apply {
34 | viewpager.adapter = pagerAdapter
35 | tablayout.setupWithViewPager(viewpager)
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/favorite/FavoriteMovieFragment.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.favorite
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.fragment.app.Fragment
7 | import androidx.lifecycle.Observer
8 | import androidx.recyclerview.widget.LinearLayoutManager
9 | import com.frogobox.base.source.model.FavoriteMovie
10 | import com.frogobox.base.BaseFragment
11 | import com.frogobox.base.BaseListener
12 | import com.frogobox.movie.R
13 | import com.frogobox.movie.databinding.FragmentTvMovieListBinding
14 | import com.frogobox.movie.mvvm.movie.DetailMovieActivity
15 | import com.frogobox.movie.mvvm.main.MainActivity
16 |
17 | /**
18 | * A simple [Fragment] subclass.
19 | */
20 | class FavoriteMovieFragment : BaseFragment(),
21 | BaseListener {
22 |
23 | private lateinit var mViewModel: FavoriteMovieViewModel
24 |
25 | override fun setupViewBinding(
26 | inflater: LayoutInflater,
27 | container: ViewGroup
28 | ): FragmentTvMovieListBinding {
29 | return FragmentTvMovieListBinding.inflate(inflater, container, false)
30 | }
31 |
32 | override fun setupViewModel() {
33 | mViewModel = (activity as MainActivity).obtainFavoriteMovieViewModel().apply {
34 |
35 | favMovieListLive.observe(viewLifecycleOwner, Observer {
36 | setupRecyclerView(it)
37 | })
38 |
39 | eventShowProgress.observe(viewLifecycleOwner, Observer {
40 | setupEventProgressView(binding?.progressBar!!, it)
41 | })
42 |
43 | eventIsEmpty.observe(viewLifecycleOwner, Observer {
44 | binding?.empty?.emptyView?.let { it1 -> setupEventEmptyView(it1, it) }
45 | })
46 |
47 | }
48 | }
49 |
50 | override fun setupUI(savedInstanceState: Bundle?) {
51 | getMovie()
52 | }
53 |
54 | override fun onResume() {
55 | super.onResume()
56 | getMovie()
57 | }
58 |
59 | private fun getMovie() {
60 | mViewModel.getFavoriteMovie()
61 | }
62 |
63 | private fun setupRecyclerView(data: List) {
64 | val adapter = com.frogobox.base.adapter.FavoriteMovieAdapter()
65 | context?.let { adapter.setRecyclerViewLayout(it, R.layout.item_list_tv_movie) }
66 | adapter.setRecyclerViewListener(this)
67 | adapter.setRecyclerViewData(data)
68 | binding?.apply {
69 | recyclerView.adapter = adapter
70 | recyclerView.layoutManager =
71 | LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
72 | }
73 | }
74 |
75 | override fun onItemClicked(data: FavoriteMovie) {
76 | context?.let {
77 | baseStartActivity(
78 | it,
79 | DetailMovieActivity.EXTRA_FAV_MOVIE,
80 | data
81 | )
82 | }
83 | }
84 |
85 | override fun onItemLongClicked(data: FavoriteMovie) {}
86 |
87 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/favorite/FavoriteMovieViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.favorite
2 |
3 | import android.app.Application
4 | import com.frogobox.base.BaseViewModel
5 | import com.frogobox.base.source.model.FavoriteMovie
6 | import com.frogobox.base.source.DataSource
7 | import com.frogobox.base.source.Repository
8 | import com.frogobox.base.util.SingleLiveEvent
9 |
10 | /**
11 | * Created by Faisal Amir
12 | * FrogoBox Inc License
13 | * =========================================
14 | * movie
15 | * Copyright (C) 16/11/2019.
16 | * All rights reserved
17 | * -----------------------------------------
18 | * Name : Muhammad Faisal Amir
19 | * E-mail : faisalamircs@gmail.com
20 | * Github : github.com/amirisback
21 | * LinkedIn : linkedin.com/in/faisalamircs
22 | * -----------------------------------------
23 | * FrogoBox Software Industries
24 | * com.frogobox.movie.viewmodel
25 | *
26 | */
27 | class FavoriteMovieViewModel(private val context: Application, private val repository: Repository) :
28 | BaseViewModel(context) {
29 |
30 | var favMovieListLive = SingleLiveEvent>()
31 |
32 | fun getFavoriteMovie() {
33 | repository.getFavoriteMovies(object :
34 | DataSource.GetLocalCallBack> {
35 | override fun onShowProgressDialog() {
36 | eventShowProgress.postValue(true)
37 | }
38 |
39 | override fun onHideProgressDialog() {
40 | eventShowProgress.postValue(false)
41 | }
42 |
43 | override fun onSuccess(data: List) {
44 | eventIsEmpty.postValue(false)
45 | favMovieListLive.postValue(data)
46 | }
47 |
48 | override fun onFinish() {
49 |
50 | }
51 |
52 | override fun onEmpty() {
53 | eventIsEmpty.postValue(true)
54 | }
55 |
56 | override fun onFailed(statusCode: Int, errorMessage: String?) {
57 |
58 | }
59 | })
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/favorite/FavoriteTvShowFragment.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.favorite
2 |
3 |
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.lifecycle.Observer
9 | import androidx.recyclerview.widget.LinearLayoutManager
10 | import com.frogobox.base.source.model.FavoriteTvShow
11 | import com.frogobox.base.adapter.FavoriteTvShowAdapter
12 | import com.frogobox.base.BaseFragment
13 | import com.frogobox.base.BaseListener
14 | import com.frogobox.movie.R
15 | import com.frogobox.movie.databinding.FragmentTvMovieListBinding
16 | import com.frogobox.movie.mvvm.tv.DetailTvShowActivity
17 | import com.frogobox.movie.mvvm.main.MainActivity
18 |
19 | /**
20 | * A simple [Fragment] subclass.
21 | */
22 | class FavoriteTvShowFragment : BaseFragment(),
23 | BaseListener {
24 |
25 | private lateinit var mViewModel: FavoriteTvShowViewModel
26 |
27 | override fun setupViewBinding(
28 | inflater: LayoutInflater,
29 | container: ViewGroup
30 | ): FragmentTvMovieListBinding {
31 | return FragmentTvMovieListBinding.inflate(inflater, container, false)
32 | }
33 |
34 | override fun setupViewModel() {
35 | mViewModel = (activity as MainActivity).obtainFavoriteTvShowViewModel().apply {
36 |
37 | favTvShowListLive.observe(viewLifecycleOwner, Observer {
38 | setupRecyclerView(it)
39 | })
40 |
41 | eventShowProgress.observe(viewLifecycleOwner, Observer {
42 | setupEventProgressView(binding?.progressBar!!, it)
43 | })
44 |
45 | eventIsEmpty.observe(viewLifecycleOwner, Observer {
46 | binding?.empty?.emptyView?.let { it1 -> setupEventEmptyView(it1, it) }
47 | })
48 |
49 | }
50 | }
51 |
52 | override fun setupUI(savedInstanceState: Bundle?) {
53 | getTvShow()
54 | }
55 |
56 | private fun getTvShow() {
57 | mViewModel.getFavoriteTvShow()
58 | }
59 |
60 | override fun onResume() {
61 | super.onResume()
62 | getTvShow()
63 | }
64 |
65 | private fun setupRecyclerView(data: List) {
66 | val adapter = FavoriteTvShowAdapter()
67 | context?.let { adapter.setRecyclerViewLayout(it, R.layout.item_list_tv_movie) }
68 | adapter.setRecyclerViewListener(this)
69 | adapter.setRecyclerViewData(data)
70 | binding?.apply {
71 | recyclerView.adapter = adapter
72 | recyclerView.layoutManager =
73 | LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
74 | }
75 | }
76 |
77 | override fun onItemClicked(data: FavoriteTvShow) {
78 | context?.let {
79 | baseStartActivity(
80 | it,
81 | DetailTvShowActivity.EXTRA_FAV_TV,
82 | data
83 | )
84 | }
85 | }
86 |
87 | override fun onItemLongClicked(data: FavoriteTvShow) {}
88 |
89 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/favorite/FavoriteTvShowViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.favorite
2 |
3 | import android.app.Application
4 | import com.frogobox.base.BaseViewModel
5 | import com.frogobox.base.source.model.FavoriteTvShow
6 | import com.frogobox.base.source.DataSource
7 | import com.frogobox.base.source.Repository
8 | import com.frogobox.base.util.SingleLiveEvent
9 |
10 | /**
11 | * Created by Faisal Amir
12 | * FrogoBox Inc License
13 | * =========================================
14 | * movie
15 | * Copyright (C) 16/11/2019.
16 | * All rights reserved
17 | * -----------------------------------------
18 | * Name : Muhammad Faisal Amir
19 | * E-mail : faisalamircs@gmail.com
20 | * Github : github.com/amirisback
21 | * LinkedIn : linkedin.com/in/faisalamircs
22 | * -----------------------------------------
23 | * FrogoBox Software Industries
24 | * com.frogobox.movie.viewmodel
25 | *
26 | */
27 | class FavoriteTvShowViewModel(private val context: Application, private val repository: Repository) :
28 | BaseViewModel(context){
29 |
30 | var favTvShowListLive = SingleLiveEvent>()
31 |
32 | fun getFavoriteTvShow(){
33 | repository.getFavoriteTvShows(object : DataSource.GetLocalCallBack>{
34 | override fun onShowProgressDialog() {
35 | eventShowProgress.postValue(true)
36 | }
37 |
38 | override fun onHideProgressDialog() {
39 | eventShowProgress.postValue(false)
40 | }
41 |
42 | override fun onSuccess(data: List) {
43 | eventIsEmpty.postValue(false)
44 | favTvShowListLive.postValue(data)
45 | }
46 |
47 | override fun onFinish() {
48 |
49 | }
50 |
51 | override fun onEmpty() {
52 | eventIsEmpty.postValue(true)
53 | }
54 |
55 | override fun onFailed(statusCode: Int, errorMessage: String?) {
56 |
57 | }
58 | })
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/main/MainActivityViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.main
2 |
3 | import android.app.Application
4 | import com.frogobox.base.BaseViewModel
5 | import com.frogobox.base.source.model.Movie
6 | import com.frogobox.base.source.DataSource
7 | import com.frogobox.base.source.Repository
8 | import com.frogobox.base.util.SingleLiveEvent
9 |
10 | /**
11 | * Created by Faisal Amir
12 | * FrogoBox Inc License
13 | * =========================================
14 | * movie
15 | * Copyright (C) 16/11/2019.
16 | * All rights reserved
17 | * -----------------------------------------
18 | * Name : Muhammad Faisal Amir
19 | * E-mail : faisalamircs@gmail.com
20 | * Github : github.com/amirisback
21 | * LinkedIn : linkedin.com/in/faisalamircs
22 | * -----------------------------------------
23 | * FrogoBox Software Industries
24 | * com.frogobox.movie.viewmodel
25 | *
26 | */
27 | class MainActivityViewModel(private val context: Application, private val repository: Repository) :
28 | BaseViewModel(context) {
29 |
30 | var eventStateReleaseReminder = SingleLiveEvent()
31 | var eventStateDailyReminder = SingleLiveEvent()
32 | var reminderLive = SingleLiveEvent>()
33 |
34 | fun getReleaseReminder(dateGte: String, dateLte: String){
35 | repository.reminderReleaseMovie(dateGte, dateLte, object : DataSource.GetRemoteCallback>{
36 | override fun onEmpty() {}
37 |
38 | override fun onShowProgressDialog() {
39 | eventShowProgress.postValue(true)
40 | }
41 |
42 | override fun onHideProgressDialog() {
43 | eventShowProgress.postValue(false)
44 | }
45 |
46 | override fun onSuccess(data: List) {
47 | reminderLive.postValue(data)
48 | }
49 |
50 | override fun onFinish() {}
51 |
52 | override fun onFailed(statusCode: Int, errorMessage: String?) {}
53 | })
54 | }
55 |
56 | fun getOprionReminder() {
57 | eventStateReleaseReminder.postValue(repository.getPrefReleaseReminder())
58 | eventStateDailyReminder.postValue(repository.getPrefDailyReminder())
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/main/MainViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.main
2 |
3 | import android.app.Application
4 | import com.frogobox.base.BaseViewModel
5 | import com.frogobox.base.source.model.Movie
6 | import com.frogobox.base.source.model.TvShow
7 | import com.frogobox.base.source.DataSource
8 | import com.frogobox.base.source.Repository
9 | import com.frogobox.base.util.SingleLiveEvent
10 |
11 | /**
12 | * Created by Faisal Amir
13 | * FrogoBox Inc License
14 | * =========================================
15 | * movie
16 | * Copyright (C) 16/11/2019.
17 | * All rights reserved
18 | * -----------------------------------------
19 | * Name : Muhammad Faisal Amir
20 | * E-mail : faisalamircs@gmail.com
21 | * Github : github.com/amirisback
22 | * LinkedIn : linkedin.com/in/faisalamircs
23 | * -----------------------------------------
24 | * FrogoBox Software Industries
25 | * com.frogobox.movie.viewmodel
26 | *
27 | */
28 | class MainViewModel(private val context: Application, private val repository: Repository) :
29 | BaseViewModel(context) {
30 |
31 | var movieListLive = SingleLiveEvent>()
32 | var tvShowListLive = SingleLiveEvent>()
33 |
34 | fun getMovie() {
35 | repository.getMovies(object : DataSource.GetRemoteCallback> {
36 | override fun onEmpty() {
37 |
38 | }
39 |
40 | override fun onShowProgressDialog() {
41 | eventShowProgress.postValue(true)
42 | }
43 |
44 | override fun onHideProgressDialog() {
45 | eventShowProgress.postValue(false)
46 | }
47 |
48 | override fun onSuccess(data: List) {
49 | movieListLive.postValue(data)
50 | }
51 |
52 | override fun onFinish() {
53 |
54 | }
55 |
56 | override fun onFailed(statusCode: Int, errorMessage: String?) {
57 |
58 | }
59 | })
60 | }
61 |
62 | fun getTvShow() {
63 | repository.getTvShow(object : DataSource.GetRemoteCallback> {
64 | override fun onEmpty() {
65 |
66 | }
67 |
68 | override fun onShowProgressDialog() {
69 | eventShowProgress.postValue(true)
70 | }
71 |
72 | override fun onHideProgressDialog() {
73 | eventShowProgress.postValue(false)
74 | }
75 |
76 | override fun onSuccess(data: List) {
77 | tvShowListLive.postValue(data)
78 | }
79 |
80 | override fun onFinish() {
81 |
82 | }
83 |
84 | override fun onFailed(statusCode: Int, errorMessage: String?) {
85 |
86 | }
87 | })
88 |
89 | }
90 |
91 |
92 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/main/SettingViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.main
2 |
3 | import android.app.Application
4 | import com.frogobox.base.BaseViewModel
5 | import com.frogobox.base.source.Repository
6 | import com.frogobox.base.util.SingleLiveEvent
7 |
8 | /**
9 | * Created by Faisal Amir
10 | * FrogoBox Inc License
11 | * =========================================
12 | * movie
13 | * Copyright (C) 16/11/2019.
14 | * All rights reserved
15 | * -----------------------------------------
16 | * Name : Muhammad Faisal Amir
17 | * E-mail : faisalamircs@gmail.com
18 | * Github : github.com/amirisback
19 | * LinkedIn : linkedin.com/in/faisalamircs
20 | * -----------------------------------------
21 | * FrogoBox Software Industries
22 | * com.frogobox.movie.viewmodel
23 | *
24 | */
25 | class SettingViewModel(private val context: Application, private val repository: Repository) :
26 | BaseViewModel(context) {
27 |
28 | var eventStateReleaseReminder = SingleLiveEvent()
29 | var eventStateDailyReminder = SingleLiveEvent()
30 |
31 | fun savePrefReleaseReminder(state: Boolean) {
32 | repository.savePrefReleaseReminder(state)
33 | }
34 |
35 | fun savePrefDailyReminder(state: Boolean) {
36 | repository.savePrefDailyReminder(state)
37 | }
38 |
39 | fun deletePrefReleaseReminder() {
40 | repository.deletePrefReleaseReminder()
41 | }
42 |
43 | fun deletePrefDailyReminder() {
44 | repository.deletePrefDailyReminder()
45 | }
46 |
47 | fun getPref() {
48 | eventStateReleaseReminder.postValue(repository.getPrefReleaseReminder())
49 | eventStateDailyReminder.postValue(repository.getPrefDailyReminder())
50 | }
51 |
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/movie/DetailMovieViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.movie
2 |
3 | import android.app.Application
4 | import com.frogobox.base.BaseViewModel
5 | import com.frogobox.base.callback.DeleteViewCallback
6 | import com.frogobox.base.callback.SaveViewCallback
7 | import com.frogobox.base.source.model.FavoriteMovie
8 | import com.frogobox.base.source.DataSource
9 | import com.frogobox.base.source.Repository
10 | import com.frogobox.base.util.SingleLiveEvent
11 |
12 | /**
13 | * Created by Faisal Amir
14 | * FrogoBox Inc License
15 | * =========================================
16 | * movie
17 | * Copyright (C) 16/11/2019.
18 | * All rights reserved
19 | * -----------------------------------------
20 | * Name : Muhammad Faisal Amir
21 | * E-mail : faisalamircs@gmail.com
22 | * Github : github.com/amirisback
23 | * LinkedIn : linkedin.com/in/faisalamircs
24 | * -----------------------------------------
25 | * FrogoBox Software Industries
26 | * com.frogobox.movie.viewmodel
27 | *
28 | */
29 | class DetailMovieViewModel(private val context: Application, private val repository: Repository) :
30 | BaseViewModel(context) {
31 |
32 | var favoriteMovie = SingleLiveEvent()
33 | var eventIsFavorite = SingleLiveEvent()
34 |
35 | fun saveFavoriteMovie(
36 | data: FavoriteMovie,
37 | callback: com.frogobox.base.callback.SaveViewCallback
38 | ) {
39 | callback.onShowProgress()
40 | if (repository.saveFavoriteMovie(context, data)) {
41 | callback.onHideProgress()
42 | callback.onSuccesInsert()
43 | eventIsEmpty.postValue(false)
44 | eventIsFavorite.postValue(true)
45 | } else {
46 | callback.onHideProgress()
47 | callback.onFailed("Failed")
48 | }
49 | }
50 |
51 | fun deleteFavoriteMovie(tableId: Int, callback: com.frogobox.base.callback.DeleteViewCallback) {
52 | callback.onShowProgress()
53 | if (repository.deleteFavoriteMovie(tableId)) {
54 | callback.onHideProgress()
55 | callback.onSuccesDelete()
56 | eventIsEmpty.postValue(true)
57 | eventIsFavorite.postValue(false)
58 | } else {
59 | callback.onHideProgress()
60 | callback.onFailed("Failed")
61 | }
62 | }
63 |
64 | fun getFavoriteMovie(id: Int) {
65 | repository.getFavoriteMovies(object :
66 | DataSource.GetLocalCallBack> {
67 | override fun onShowProgressDialog() {
68 | eventShowProgress.postValue(true)
69 | }
70 |
71 | override fun onHideProgressDialog() {
72 | eventShowProgress.postValue(false)
73 | }
74 |
75 | override fun onSuccess(data: List) {
76 |
77 | val tempFavoriteList = mutableListOf()
78 | tempFavoriteList.clear()
79 | tempFavoriteList.addAll(data)
80 |
81 | for (i in tempFavoriteList.indices) {
82 | if (tempFavoriteList[i].id!! == id) {
83 | eventIsEmpty.postValue(false)
84 | eventIsFavorite.postValue(true)
85 | favoriteMovie.postValue(tempFavoriteList[i])
86 | break
87 | } else {
88 | eventIsFavorite.postValue(false)
89 | eventIsEmpty.postValue(true)
90 | }
91 | }
92 | }
93 |
94 | override fun onFinish() {}
95 |
96 | override fun onEmpty() {
97 | eventIsEmpty.postValue(true)
98 | eventIsFavorite.postValue(false)
99 | }
100 |
101 | override fun onFailed(statusCode: Int, errorMessage: String?) {}
102 | })
103 | }
104 |
105 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/movie/MovieFragment.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.movie
2 |
3 |
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.lifecycle.Observer
9 | import androidx.recyclerview.widget.StaggeredGridLayoutManager
10 | import com.frogobox.base.source.model.Movie
11 | import com.frogobox.base.adapter.MovieAdapter
12 | import com.frogobox.base.BaseFragment
13 | import com.frogobox.base.BaseListener
14 | import com.frogobox.movie.R
15 | import com.frogobox.movie.databinding.FragmentTvMovieGridBinding
16 | import com.frogobox.movie.mvvm.main.MainActivity
17 | import com.frogobox.movie.mvvm.main.MainViewModel
18 |
19 | /**
20 | * A simple [Fragment] subclass.
21 | */
22 | class MovieFragment : BaseFragment(),
23 | BaseListener {
24 |
25 | private lateinit var mViewModel: MainViewModel
26 |
27 | override fun setupViewBinding(
28 | inflater: LayoutInflater,
29 | container: ViewGroup
30 | ): FragmentTvMovieGridBinding {
31 | return FragmentTvMovieGridBinding.inflate(inflater, container, false)
32 | }
33 |
34 | override fun setupViewModel() {
35 | mViewModel = (activity as MainActivity).obtainMainViewModel().apply {
36 |
37 | movieListLive.observe(viewLifecycleOwner, Observer {
38 | setupRecyclerView(it)
39 | })
40 |
41 | eventShowProgress.observe(viewLifecycleOwner, Observer {
42 | setupEventProgressView(binding?.progressBar!!, it)
43 | })
44 |
45 | }
46 | }
47 |
48 | override fun setupUI(savedInstanceState: Bundle?) {
49 | getMovies()
50 | }
51 |
52 | private fun getMovies() {
53 | mActivity.setTitle(getString(R.string.title_movie))
54 | mViewModel.getMovie()
55 | }
56 |
57 | private fun setupRecyclerView(data: List) {
58 | val adapter = MovieAdapter()
59 | context?.let { adapter.setRecyclerViewLayout(it, R.layout.item_grid_tv_movie) }
60 | adapter.setRecyclerViewListener(this)
61 | adapter.setRecyclerViewData(data)
62 | binding?.apply {
63 | recyclerView.adapter = adapter
64 | recyclerView.layoutManager =
65 | StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
66 | }
67 | }
68 |
69 | override fun onItemClicked(data: Movie) {
70 | context?.let {
71 | baseStartActivity(
72 | it,
73 | DetailMovieActivity.EXTRA_MOVIE,
74 | data
75 | )
76 | }
77 | }
78 |
79 | override fun onItemLongClicked(data: Movie) {}
80 |
81 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/movie/SearchMovieActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.movie
2 |
3 | import android.os.Bundle
4 | import android.text.Editable
5 | import android.text.TextWatcher
6 | import androidx.lifecycle.Observer
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import com.frogobox.base.source.model.Movie
9 | import com.frogobox.base.adapter.MovieAdapter
10 | import com.frogobox.base.BaseListener
11 | import com.frogobox.movie.R
12 | import com.frogobox.movie.databinding.ActivitySearchBinding
13 | import com.frogobox.movie.util.BaseAppActivity
14 |
15 | class SearchMovieActivity : BaseAppActivity(),
16 | BaseListener {
17 |
18 | private lateinit var mViewModel: SearchMovieViewModel
19 | private lateinit var adapter: MovieAdapter
20 |
21 | override fun setupViewBinding(): ActivitySearchBinding {
22 | return ActivitySearchBinding.inflate(layoutInflater)
23 | }
24 |
25 | override fun setupViewModel() {
26 | adapter = MovieAdapter()
27 |
28 | mViewModel = obtainSearchMovieViewModel().apply {
29 |
30 | movieListLive.observe(this@SearchMovieActivity, Observer {
31 | setupRecyclerView(it)
32 | })
33 |
34 | eventShowProgress.observe(this@SearchMovieActivity, Observer {
35 | setupEventProgressView(binding.progressBar, it)
36 | })
37 |
38 | }
39 | }
40 |
41 | override fun setupUI(savedInstanceState: Bundle?) {
42 | setupViewElement()
43 | }
44 |
45 | private fun obtainSearchMovieViewModel(): SearchMovieViewModel =
46 | obtainViewModel(SearchMovieViewModel::class.java)
47 |
48 | private fun searchMovie(query: String) {
49 | mViewModel.searchMovies(query)
50 | }
51 |
52 | private fun setupViewElement() {
53 |
54 | binding.toolbar.apply {
55 | etSearch.addTextChangedListener(object : TextWatcher {
56 | override fun afterTextChanged(p0: Editable?) {}
57 | override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
58 | override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
59 | val query = etSearch.text.toString()
60 | if (!query.equals("")) {
61 | searchMovie(query)
62 | } else {
63 | adapter.nukeRecyclerViewData()
64 | }
65 | }
66 | })
67 |
68 | ivBack.setOnClickListener {
69 | finish()
70 | }
71 |
72 | ivClose.setOnClickListener {
73 | etSearch.text.clear()
74 | }
75 | }
76 | }
77 |
78 | private fun setupRecyclerView(data: List) {
79 | adapter.setRecyclerViewLayout(this, R.layout.item_list_tv_movie)
80 | adapter.setRecyclerViewListener(this)
81 | adapter.setRecyclerViewData(data)
82 | binding.apply {
83 | recyclerView.adapter = adapter
84 | recyclerView.layoutManager =
85 | LinearLayoutManager(this@SearchMovieActivity, LinearLayoutManager.VERTICAL, false)
86 | }
87 | }
88 |
89 | override fun onItemClicked(data: Movie) {
90 | baseStartActivity(
91 | this,
92 | DetailMovieActivity.EXTRA_MOVIE, data
93 | )
94 | }
95 |
96 | override fun onItemLongClicked(data: Movie) {}
97 |
98 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/movie/SearchMovieViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.movie
2 |
3 | import android.app.Application
4 | import com.frogobox.base.BaseViewModel
5 | import com.frogobox.base.source.model.Movie
6 | import com.frogobox.base.source.DataSource
7 | import com.frogobox.base.source.Repository
8 | import com.frogobox.base.util.SingleLiveEvent
9 |
10 | /**
11 | * Created by Faisal Amir
12 | * FrogoBox Inc License
13 | * =========================================
14 | * movie
15 | * Copyright (C) 16/11/2019.
16 | * All rights reserved
17 | * -----------------------------------------
18 | * Name : Muhammad Faisal Amir
19 | * E-mail : faisalamircs@gmail.com
20 | * Github : github.com/amirisback
21 | * LinkedIn : linkedin.com/in/faisalamircs
22 | * -----------------------------------------
23 | * FrogoBox Software Industries
24 | * com.frogobox.movie.viewmodel
25 | *
26 | */
27 | class SearchMovieViewModel(private val context: Application, private val repository: Repository) :
28 | BaseViewModel(context) {
29 |
30 | var movieListLive = SingleLiveEvent>()
31 |
32 | fun searchMovies(query: String) {
33 | repository.searchMovies(query, object : DataSource.GetRemoteCallback> {
34 | override fun onEmpty() {
35 |
36 | }
37 |
38 | override fun onShowProgressDialog() {
39 | eventShowProgress.postValue(true)
40 | }
41 |
42 | override fun onHideProgressDialog() {
43 | eventShowProgress.postValue(false)
44 | }
45 |
46 | override fun onSuccess(data: List) {
47 | movieListLive.postValue(data)
48 | }
49 |
50 | override fun onFinish() {
51 |
52 | }
53 |
54 | override fun onFailed(statusCode: Int, errorMessage: String?) {
55 |
56 | }
57 | })
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/tv/DetailTvShowViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.tv
2 |
3 | import android.app.Application
4 | import com.frogobox.base.BaseViewModel
5 | import com.frogobox.base.callback.DeleteViewCallback
6 | import com.frogobox.base.callback.SaveViewCallback
7 | import com.frogobox.base.source.model.FavoriteTvShow
8 | import com.frogobox.base.source.DataSource
9 | import com.frogobox.base.source.Repository
10 | import com.frogobox.base.util.SingleLiveEvent
11 |
12 | /**
13 | * Created by Faisal Amir
14 | * FrogoBox Inc License
15 | * =========================================
16 | * movie
17 | * Copyright (C) 16/11/2019.
18 | * All rights reserved
19 | * -----------------------------------------
20 | * Name : Muhammad Faisal Amir
21 | * E-mail : faisalamircs@gmail.com
22 | * Github : github.com/amirisback
23 | * LinkedIn : linkedin.com/in/faisalamircs
24 | * -----------------------------------------
25 | * FrogoBox Software Industries
26 | * com.frogobox.movie.viewmodel
27 | *
28 | */
29 | class DetailTvShowViewModel(private val context: Application, private val repository: Repository) :
30 | BaseViewModel(context) {
31 |
32 | var favoriteTvShow = SingleLiveEvent()
33 | var eventIsFavorite = SingleLiveEvent()
34 |
35 | fun saveFavoriteTvShow(data: FavoriteTvShow, callback: com.frogobox.base.callback.SaveViewCallback){
36 | callback.onShowProgress()
37 | if (repository.saveFavoriteTvShow(context, data)){
38 | callback.onHideProgress()
39 | callback.onSuccesInsert()
40 | eventIsFavorite.postValue(true)
41 | } else {
42 | callback.onHideProgress()
43 | callback.onFailed("Failed")
44 | }
45 | }
46 |
47 | fun deleteFavoriteTvShow(tableId: Int, callback: com.frogobox.base.callback.DeleteViewCallback){
48 | callback.onShowProgress()
49 | if (repository.deleteFavoriteTvShow(tableId)){
50 | callback.onHideProgress()
51 | callback.onSuccesDelete()
52 | eventIsFavorite.postValue(false)
53 | } else {
54 | callback.onHideProgress()
55 | callback.onFailed("Failed")
56 | }
57 | }
58 |
59 | fun getFavoriteTvShow(id: Int){
60 | repository.getFavoriteTvShows(object : DataSource.GetLocalCallBack>{
61 | override fun onShowProgressDialog() {
62 | eventShowProgress.postValue(true)
63 | }
64 |
65 | override fun onHideProgressDialog() {
66 | eventShowProgress.postValue(false)
67 | }
68 |
69 | override fun onSuccess(data: List) {
70 |
71 | val tempFavoriteList = mutableListOf()
72 | tempFavoriteList.clear()
73 | tempFavoriteList.addAll(data)
74 |
75 | for (i in tempFavoriteList.indices) {
76 | if (tempFavoriteList[i].id!! == id) {
77 | eventIsEmpty.postValue(false)
78 | eventIsFavorite.postValue(true)
79 | favoriteTvShow.postValue(tempFavoriteList[i])
80 | break
81 | } else {
82 | eventIsEmpty.postValue(true)
83 | eventIsFavorite.postValue(false)
84 | }
85 | }
86 | }
87 |
88 | override fun onFinish() {}
89 |
90 | override fun onEmpty() {
91 | eventIsEmpty.postValue(true)
92 | eventIsFavorite.postValue(false)
93 | }
94 |
95 | override fun onFailed(statusCode: Int, errorMessage: String?) {}
96 | })
97 | }
98 |
99 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/tv/SearchTvShowActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.tv
2 |
3 | import android.os.Bundle
4 | import android.text.Editable
5 | import android.text.TextWatcher
6 | import androidx.lifecycle.Observer
7 | import androidx.recyclerview.widget.LinearLayoutManager
8 | import com.frogobox.base.source.model.TvShow
9 | import com.frogobox.base.adapter.TvShowAdapter
10 | import com.frogobox.base.BaseListener
11 | import com.frogobox.movie.R
12 | import com.frogobox.movie.databinding.ActivitySearchBinding
13 | import com.frogobox.movie.util.BaseAppActivity
14 |
15 | class SearchTvShowActivity : BaseAppActivity(),
16 | BaseListener {
17 |
18 | private lateinit var mViewModel: SearchTvShowViewModel
19 | private lateinit var adapter: TvShowAdapter
20 |
21 | override fun setupViewBinding(): ActivitySearchBinding {
22 | return ActivitySearchBinding.inflate(layoutInflater)
23 | }
24 |
25 | override fun setupViewModel() {
26 | adapter = TvShowAdapter()
27 |
28 | mViewModel = obtainSearchTvShowViewModel().apply {
29 |
30 | tvShowListLive.observe(this@SearchTvShowActivity, Observer {
31 | setupRecyclerView(it)
32 | })
33 |
34 | eventShowProgress.observe(this@SearchTvShowActivity, Observer {
35 | setupEventProgressView(binding.progressBar, it)
36 | })
37 |
38 | }
39 | }
40 |
41 |
42 | override fun setupUI(savedInstanceState: Bundle?) {
43 | setupViewElement()
44 | }
45 |
46 | fun obtainSearchTvShowViewModel(): SearchTvShowViewModel =
47 | obtainViewModel(SearchTvShowViewModel::class.java)
48 |
49 | private fun searchTvShow(query: String) {
50 | mViewModel.searchTvShow(query)
51 | }
52 |
53 | private fun setupViewElement() {
54 | binding.toolbar.apply {
55 | etSearch.addTextChangedListener(object : TextWatcher {
56 | override fun afterTextChanged(p0: Editable?) {}
57 | override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
58 | override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
59 | val query = etSearch.text.toString()
60 | if (!query.equals("")) {
61 | searchTvShow(query)
62 | } else {
63 | adapter.nukeRecyclerViewData()
64 | }
65 | }
66 | })
67 |
68 | ivBack.setOnClickListener {
69 | finish()
70 | }
71 |
72 | ivClose.setOnClickListener {
73 | etSearch.text.clear()
74 | }
75 | }
76 | }
77 |
78 | private fun setupRecyclerView(data: List) {
79 | adapter.setRecyclerViewLayout(this, R.layout.item_list_tv_movie)
80 | adapter.setRecyclerViewListener(this)
81 | adapter.setRecyclerViewData(data)
82 | binding.apply {
83 | recyclerView.adapter = adapter
84 | recyclerView.layoutManager =
85 | LinearLayoutManager(this@SearchTvShowActivity, LinearLayoutManager.VERTICAL, false)
86 | }
87 | }
88 |
89 | override fun onItemClicked(data: TvShow) {
90 | baseStartActivity(
91 | this,
92 | DetailTvShowActivity.EXTRA_TV, data
93 | )
94 | }
95 |
96 | override fun onItemLongClicked(data: TvShow) {}
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/tv/SearchTvShowViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.tv
2 |
3 | import android.app.Application
4 | import com.frogobox.base.BaseViewModel
5 | import com.frogobox.base.source.model.TvShow
6 | import com.frogobox.base.source.DataSource
7 | import com.frogobox.base.source.Repository
8 | import com.frogobox.base.util.SingleLiveEvent
9 |
10 | /**
11 | * Created by Faisal Amir
12 | * FrogoBox Inc License
13 | * =========================================
14 | * movie
15 | * Copyright (C) 16/11/2019.
16 | * All rights reserved
17 | * -----------------------------------------
18 | * Name : Muhammad Faisal Amir
19 | * E-mail : faisalamircs@gmail.com
20 | * Github : github.com/amirisback
21 | * LinkedIn : linkedin.com/in/faisalamircs
22 | * -----------------------------------------
23 | * FrogoBox Software Industries
24 | * com.frogobox.movie.viewmodel
25 | *
26 | */
27 | class SearchTvShowViewModel (private val context: Application, private val repository: Repository) :
28 | BaseViewModel(context) {
29 |
30 | var tvShowListLive = SingleLiveEvent>()
31 |
32 | fun searchTvShow(query: String){
33 | repository.searchTvShow(query, object : DataSource.GetRemoteCallback>{
34 | override fun onEmpty() {
35 |
36 | }
37 |
38 | override fun onShowProgressDialog() {
39 | eventShowProgress.postValue(true)
40 | }
41 |
42 | override fun onHideProgressDialog() {
43 | eventShowProgress.postValue(false)
44 | }
45 |
46 | override fun onSuccess(data: List) {
47 | tvShowListLive.postValue(data)
48 | }
49 |
50 | override fun onFinish() {
51 |
52 | }
53 |
54 | override fun onFailed(statusCode: Int, errorMessage: String?) {
55 |
56 | }
57 | })
58 |
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/mvvm/tv/TvShowFragment.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.mvvm.tv
2 |
3 |
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.lifecycle.Observer
9 | import androidx.recyclerview.widget.LinearLayoutManager
10 | import androidx.recyclerview.widget.StaggeredGridLayoutManager
11 | import com.frogobox.base.source.model.TvShow
12 | import com.frogobox.base.adapter.TvShowAdapter
13 | import com.frogobox.base.BaseFragment
14 | import com.frogobox.base.BaseListener
15 | import com.frogobox.movie.R
16 | import com.frogobox.movie.databinding.FragmentTvMovieGridBinding
17 | import com.frogobox.movie.mvvm.main.MainActivity
18 | import com.frogobox.movie.mvvm.main.MainViewModel
19 |
20 | /**
21 | * A simple [Fragment] subclass.
22 | */
23 | class TvShowFragment : BaseFragment(),
24 | BaseListener {
25 |
26 | private lateinit var mViewModel: MainViewModel
27 |
28 | override fun setupViewBinding(
29 | inflater: LayoutInflater,
30 | container: ViewGroup
31 | ): FragmentTvMovieGridBinding {
32 | return FragmentTvMovieGridBinding.inflate(inflater, container, false)
33 | }
34 |
35 | override fun setupViewModel() {
36 | mViewModel = (activity as MainActivity).obtainMainViewModel().apply {
37 |
38 | tvShowListLive.observe(viewLifecycleOwner, Observer {
39 | setupRecyclerView(it)
40 | })
41 |
42 | eventShowProgress.observe(viewLifecycleOwner, Observer {
43 | setupEventProgressView(binding?.progressBar!!, it)
44 | })
45 |
46 | }
47 | }
48 |
49 | override fun setupUI(savedInstanceState: Bundle?) {
50 | getTvShow()
51 | }
52 |
53 | private fun getTvShow() {
54 | mActivity.title = getString(R.string.title_tv)
55 | mViewModel.getTvShow()
56 | }
57 |
58 | private fun setupRecyclerView(data: List) {
59 | val adapter = TvShowAdapter()
60 | context?.let { adapter.setRecyclerViewLayout(it, R.layout.item_grid_tv_movie) }
61 | adapter.setRecyclerViewListener(this)
62 | adapter.setRecyclerViewData(data)
63 | binding?.apply {
64 | recyclerView.adapter = adapter
65 | recyclerView.layoutManager =
66 | LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
67 | recyclerView.layoutManager =
68 | StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
69 | }
70 | }
71 |
72 | override fun onItemClicked(data: TvShow) {
73 | context?.let {
74 | baseStartActivity(
75 | it,
76 | DetailTvShowActivity.EXTRA_TV,
77 | data
78 | )
79 | }
80 | }
81 |
82 | override fun onItemLongClicked(data: TvShow) {}
83 |
84 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/util/BaseAppActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.util
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 | import androidx.viewbinding.ViewBinding
6 | import com.frogobox.base.BaseActivity
7 |
8 | /**
9 | * Created by Faisal Amir
10 | * FrogoBox Inc License
11 | * =========================================
12 | * movie
13 | * Copyright (C) 16/11/2019.
14 | * All rights reserved
15 | * -----------------------------------------
16 | * Name : Muhammad Faisal Amir
17 | * E-mail : faisalamircs@gmail.com
18 | * Github : github.com/amirisback
19 | * LinkedIn : linkedin.com/in/faisalamircs
20 | * -----------------------------------------
21 | * FrogoBox Software Industries
22 | * com.frogobox.movie.util
23 | *
24 | */
25 | abstract class BaseAppActivity : BaseActivity() {
26 |
27 | fun obtainViewModel(viewModelClass: Class) =
28 | ViewModelProvider(this, ViewModelFactory.getInstance(application)).get(viewModelClass)
29 |
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/util/ViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.util
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Application
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.ViewModelProvider
7 | import com.frogobox.base.source.Repository
8 | import com.frogobox.base.util.Injection
9 | import com.frogobox.movie.mvvm.favorite.FavoriteMovieViewModel
10 | import com.frogobox.movie.mvvm.favorite.FavoriteTvShowViewModel
11 | import com.frogobox.movie.mvvm.main.MainActivityViewModel
12 | import com.frogobox.movie.mvvm.main.MainViewModel
13 | import com.frogobox.movie.mvvm.main.SettingViewModel
14 | import com.frogobox.movie.mvvm.movie.DetailMovieViewModel
15 | import com.frogobox.movie.mvvm.movie.SearchMovieViewModel
16 | import com.frogobox.movie.mvvm.tv.DetailTvShowViewModel
17 | import com.frogobox.movie.mvvm.tv.SearchTvShowViewModel
18 |
19 | /**
20 | * Created by Faisal Amir
21 | * FrogoBox Inc License
22 | * =========================================
23 | * movie
24 | * Copyright (C) 16/11/2019.
25 | * All rights reserved
26 | * -----------------------------------------
27 | * Name : Muhammad Faisal Amir
28 | * E-mail : faisalamircs@gmail.com
29 | * Github : github.com/amirisback
30 | * LinkedIn : linkedin.com/in/faisalamircs
31 | * -----------------------------------------
32 | * FrogoBox Software Industries
33 | * com.frogobox.movie.util
34 | *
35 | */
36 | class ViewModelFactory private constructor(
37 | private val mApplication: Application,
38 | private val repository: Repository
39 | ) : ViewModelProvider.NewInstanceFactory() {
40 |
41 | @Suppress("UNCHECKED_CAST")
42 | override fun create(modelClass: Class): T =
43 | with(modelClass) {
44 | when {
45 |
46 | isAssignableFrom(MainActivityViewModel::class.java) ->
47 | MainActivityViewModel(mApplication, repository)
48 |
49 | isAssignableFrom(MainViewModel::class.java) ->
50 | MainViewModel(mApplication, repository)
51 |
52 | isAssignableFrom(DetailMovieViewModel::class.java) ->
53 | DetailMovieViewModel(mApplication, repository)
54 |
55 | isAssignableFrom(DetailTvShowViewModel::class.java) ->
56 | DetailTvShowViewModel(mApplication, repository)
57 |
58 | isAssignableFrom(FavoriteMovieViewModel::class.java) ->
59 | FavoriteMovieViewModel(mApplication, repository)
60 |
61 | isAssignableFrom(FavoriteTvShowViewModel::class.java) ->
62 | FavoriteTvShowViewModel(mApplication, repository)
63 |
64 | isAssignableFrom(SearchMovieViewModel::class.java) ->
65 | SearchMovieViewModel(mApplication, repository)
66 |
67 | isAssignableFrom(SearchTvShowViewModel::class.java) ->
68 | SearchTvShowViewModel(mApplication, repository)
69 |
70 | isAssignableFrom(SettingViewModel::class.java) ->
71 | SettingViewModel(mApplication, repository)
72 |
73 | else ->
74 | throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
75 | }
76 | } as T
77 |
78 | companion object {
79 |
80 | @SuppressLint("StaticFieldLeak")
81 | @Volatile private var INSTANCE: ViewModelFactory? = null
82 |
83 | fun getInstance(mApplication: Application) =
84 | INSTANCE
85 | ?: synchronized(ViewModelFactory::class.java) {
86 | INSTANCE
87 | ?: ViewModelFactory(
88 | mApplication,
89 | Injection.provideRepository(mApplication.applicationContext)
90 | )
91 | .also { INSTANCE = it }
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/widget/FavoriteBannerWidget.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.widget
2 |
3 | import android.app.PendingIntent
4 | import android.appwidget.AppWidgetManager
5 | import android.appwidget.AppWidgetProvider
6 | import android.content.Context
7 | import android.content.Intent
8 | import android.net.Uri
9 | import android.widget.RemoteViews
10 | import android.widget.Toast
11 | import com.frogobox.movie.R
12 |
13 | /**
14 | * Created by Faisal Amir
15 | * FrogoBox Inc License
16 | * =========================================
17 | * movie
18 | * Copyright (C) 16/11/2019.
19 | * All rights reserved
20 | * -----------------------------------------
21 | * Name : Muhammad Faisal Amir
22 | * E-mail : faisalamircs@gmail.com
23 | * Github : github.com/amirisback
24 | * LinkedIn : linkedin.com/in/faisalamircs
25 | * -----------------------------------------
26 | * FrogoBox Software Industries
27 | * com.frogobox.movie.ui.widget
28 | *
29 | */
30 | class FavoriteBannerWidget : AppWidgetProvider() {
31 |
32 | override fun onUpdate(
33 | context: Context,
34 | appWidgetManager: AppWidgetManager,
35 | appWidgetIds: IntArray
36 | ) {
37 | // There may be multiple widgets active, so update all of them
38 | for (appWidgetId in appWidgetIds) {
39 | updateAppWidget(context, appWidgetManager, appWidgetId)
40 | }
41 | }
42 |
43 | override fun onEnabled(context: Context) {
44 | // Enter relevant functionality for when the first widget is created
45 | }
46 |
47 | override fun onDisabled(context: Context) {
48 | // Enter relevant functionality for when the last widget is disabled
49 | }
50 |
51 | override fun onReceive(context: Context, intent: Intent) {
52 | val mgr = AppWidgetManager.getInstance(context)
53 | if (intent.action == TOAST_ACTION) {
54 | val appWidgetId = intent.getIntExtra(
55 | AppWidgetManager.EXTRA_APPWIDGET_ID,
56 | AppWidgetManager.INVALID_APPWIDGET_ID
57 | )
58 | val viewIndex = intent.getIntExtra(EXTRA_ITEM, 0) + 1
59 | Toast.makeText(context, "Favorite Movie Number : $viewIndex", Toast.LENGTH_SHORT).show()
60 | }
61 | super.onReceive(context, intent)
62 | }
63 |
64 | companion object {
65 |
66 | val TOAST_ACTION = "toast_action"
67 | val EXTRA_ITEM = "extra_movie"
68 |
69 | internal fun updateAppWidget(
70 | context: Context, appWidgetManager: AppWidgetManager,
71 | appWidgetId: Int
72 | ) {
73 |
74 | val intent = Intent(context, StackWidgetService::class.java)
75 | intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
76 | intent.data = Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))
77 |
78 | val views = RemoteViews(context.packageName, R.layout.widget_banner_favorite)
79 | views.setRemoteAdapter(R.id.stack_view, intent)
80 | views.setEmptyView(R.id.stack_view, R.id.empty_view)
81 |
82 | val toastIntent = Intent(context, FavoriteBannerWidget::class.java)
83 | toastIntent.action = TOAST_ACTION
84 | toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
85 |
86 | intent.data = Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))
87 | val toastPendingIntent = PendingIntent.getBroadcast(
88 | context,
89 | 0,
90 | toastIntent,
91 | PendingIntent.FLAG_UPDATE_CURRENT
92 | )
93 | views.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent)
94 |
95 | appWidgetManager.updateAppWidget(appWidgetId, views)
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/frogobox/movie/widget/StackWidgetService.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.movie.widget
2 |
3 | import android.content.Intent
4 | import android.widget.RemoteViewsService
5 |
6 | /**
7 | * Created by Faisal Amir
8 | * FrogoBox Inc License
9 | * =========================================
10 | * movie
11 | * Copyright (C) 16/11/2019.
12 | * All rights reserved
13 | * -----------------------------------------
14 | * Name : Muhammad Faisal Amir
15 | * E-mail : faisalamircs@gmail.com
16 | * Github : github.com/amirisback
17 | * LinkedIn : linkedin.com/in/faisalamircs
18 | * -----------------------------------------
19 | * FrogoBox Software Industries
20 | * com.frogobox.movie.ui.widget
21 | *
22 | */
23 | class StackWidgetService : RemoteViewsService() {
24 |
25 | override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
26 | return StackRemoteViewFactory(this.applicationContext, intent)
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
30 |
33 |
36 |
39 |
42 |
45 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
20 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
14 |
15 |
26 |
27 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_favorite.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
23 |
24 |
33 |
34 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_tv_movie_grid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
21 |
22 |
32 |
33 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_tv_movie_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
30 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/toolbar_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
19 |
20 |
27 |
28 |
41 |
42 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_banner_favorite.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_content_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
15 |
16 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hello blank fragment
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/favorite_banner_widget_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/base/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/base/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/base/consumer-rules.pro
--------------------------------------------------------------------------------
/base/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/base/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/BaseApiModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | /**
6 | * Created by Faisal Amir
7 | * FrogoBox Inc License
8 | * =========================================
9 | * movie
10 | * Copyright (C) 16/11/2019.
11 | * All rights reserved
12 | * -----------------------------------------
13 | * Name : Muhammad Faisal Amir
14 | * E-mail : faisalamircs@gmail.com
15 | * Github : github.com/amirisback
16 | * LinkedIn : linkedin.com/in/faisalamircs
17 | * -----------------------------------------
18 | * FrogoBox Software Industries
19 | * com.frogobox.base
20 | *
21 | */
22 | data class BaseApiModel(
23 | @SerializedName("code") val code: Int,
24 | @SerializedName("message") val message: String,
25 | @SerializedName("data") val data: T? = null,
26 |
27 | // Remove code below if project is running
28 | var page: Int,
29 | var total_results: Int,
30 | var total_pages: Int,
31 | var results: T? = null
32 | )
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/BaseApplication.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base
2 |
3 | import android.annotation.TargetApi
4 | import android.app.Application
5 | import android.content.Context
6 | import android.os.Build
7 | import android.preference.PreferenceManager
8 | import java.util.*
9 |
10 | /**
11 | * Created by Faisal Amir
12 | * FrogoBox Inc License
13 | * =========================================
14 | * movie
15 | * Copyright (C) 16/11/2019.
16 | * All rights reserved
17 | * -----------------------------------------
18 | * Name : Muhammad Faisal Amir
19 | * E-mail : faisalamircs@gmail.com
20 | * Github : github.com/amirisback
21 | * LinkedIn : linkedin.com/in/faisalamircs
22 | * -----------------------------------------
23 | * FrogoBox Software Industries
24 | * com.frogobox.base
25 | *
26 | */
27 | class BaseApplication : Application() {
28 |
29 | private val SELECTED_LANGUAGE = "Locale.Helper.Selected.Language"
30 |
31 | fun onAttach(context: Context, defaultLanguage: String): Context {
32 | val lang = getPersistedData(context, defaultLanguage)
33 | return setLocale(context, lang)
34 | }
35 |
36 | fun setLocale(context: Context, language: String?): Context {
37 | persist(context, language)
38 |
39 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
40 | updateResources(context, language)
41 | } else updateResourcesLegacy(context, language)
42 |
43 | }
44 |
45 | private fun getPersistedData(context: Context, defaultLanguage: String): String? {
46 | val preferences = PreferenceManager.getDefaultSharedPreferences(context)
47 | return preferences.getString(SELECTED_LANGUAGE, defaultLanguage)
48 | }
49 |
50 | private fun persist(context: Context, language: String?) {
51 | val preferences = PreferenceManager.getDefaultSharedPreferences(context)
52 | val editor = preferences.edit()
53 |
54 | editor.putString(SELECTED_LANGUAGE, language)
55 | editor.apply()
56 | }
57 |
58 | @TargetApi(Build.VERSION_CODES.N)
59 | private fun updateResources(context: Context, language: String?): Context {
60 | val locale = Locale(language)
61 | Locale.setDefault(locale)
62 |
63 | val configuration = context.resources.configuration
64 | configuration.setLocale(locale)
65 | configuration.setLayoutDirection(locale)
66 |
67 | return context.createConfigurationContext(configuration)
68 | }
69 |
70 | private fun updateResourcesLegacy(context: Context, language: String?): Context {
71 | val locale = Locale(language)
72 | Locale.setDefault(locale)
73 |
74 | val resources = context.resources
75 |
76 | val configuration = resources.configuration
77 | configuration.locale = locale
78 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
79 | configuration.setLayoutDirection(locale)
80 | }
81 |
82 | resources.updateConfiguration(configuration, resources.displayMetrics)
83 |
84 | return context
85 | }
86 |
87 | override fun onCreate() {
88 | super.onCreate()
89 | instance = this
90 |
91 | }
92 |
93 | override fun attachBaseContext(base: Context) {
94 | super.attachBaseContext(onAttach(base, "en"))
95 | }
96 |
97 | companion object {
98 | lateinit var instance: BaseApplication
99 | fun getContext(): Context = instance.applicationContext
100 | }
101 |
102 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/BaseCallback.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base
2 |
3 | import com.google.gson.Gson
4 | import io.reactivex.rxjava3.core.SingleObserver
5 | import io.reactivex.rxjava3.disposables.Disposable
6 | import retrofit2.HttpException
7 | import java.net.SocketTimeoutException
8 | import java.net.UnknownHostException
9 |
10 | /**
11 | * Created by Faisal Amir
12 | * FrogoBox Inc License
13 | * =========================================
14 | * movie
15 | * Copyright (C) 16/11/2019.
16 | * All rights reserved
17 | * -----------------------------------------
18 | * Name : Muhammad Faisal Amir
19 | * E-mail : faisalamircs@gmail.com
20 | * Github : github.com/amirisback
21 | * LinkedIn : linkedin.com/in/faisalamircs
22 | * -----------------------------------------
23 | * FrogoBox Software Industries
24 | * com.frogobox.base
25 | *
26 | */
27 | abstract class BaseCallback : SingleObserver {
28 |
29 | abstract fun onCallbackSucces(data: M)
30 | abstract fun onCallbackError(code: Int, errorMessage: String)
31 | abstract fun onAddSubscribe(disposable: Disposable)
32 | abstract fun onCompleted()
33 |
34 | override fun onSuccess(t: M) {
35 | onCompleted()
36 | if (t == null) {
37 | onCallbackError(200,"Data is empty")
38 | } else {
39 | onCallbackSucces(t)
40 | }
41 | }
42 |
43 | override fun onSubscribe(d: Disposable) {
44 | onAddSubscribe(d)
45 | }
46 |
47 | override fun onError(e: Throwable) {
48 | onCompleted()
49 | e.printStackTrace()
50 | when (e) {
51 | is HttpException -> {
52 | val code = e.code()
53 | var msg = e.message()
54 | var baseDao: BaseApiModel? = null
55 | try {
56 | val body = e.response()?.errorBody()
57 | baseDao = Gson().fromJson>(body!!.string(), BaseApiModel::class.java)
58 | } catch (exception: Exception) {
59 | onCallbackError(code, exception.message!!)
60 | }
61 |
62 | when (code) {
63 | 504 -> {
64 | msg = baseDao?.message?: "Error Response"
65 | }
66 | 502, 404 -> {
67 | msg = baseDao?.message?: "Error Connect or Resource Not Found"
68 | }
69 | 400 -> {
70 | msg = baseDao?.message?: "Bad Request"
71 | }
72 | 401 -> {
73 | msg = baseDao?.message?: "Not Authorized"
74 | }
75 | }
76 |
77 | onCallbackError(code, msg)
78 | }
79 |
80 | is UnknownHostException -> onCallbackError(-1, "Telah terjadi kesalahan ketika koneksi ke server: ${e.message}")
81 | is SocketTimeoutException -> onCallbackError(-1, "Telah terjadi kesalahan ketika koneksi ke server: ${e.message}")
82 | else -> onCallbackError(-1, e.message ?: "Unknown error occured")
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/BaseDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.AndroidViewModel
5 |
6 | /**
7 | * Created by Faisal Amir
8 | * FrogoBox Inc License
9 | * =========================================
10 | * movie
11 | * Copyright (C) 16/11/2019.
12 | * All rights reserved
13 | * -----------------------------------------
14 | * Name : Muhammad Faisal Amir
15 | * E-mail : faisalamircs@gmail.com
16 | * Github : github.com/amirisback
17 | * LinkedIn : linkedin.com/in/faisalamircs
18 | * -----------------------------------------
19 | * FrogoBox Software Industries
20 | * com.frogobox.base
21 | *
22 | */
23 | interface BaseDataSource {
24 | interface ResponseCallback {
25 | fun onShowProgressDialog()
26 | fun onHideProgressDialog()
27 | fun onSuccess(data: T)
28 | fun onFinish()
29 | fun onEmpty()
30 | fun onFailed(statusCode: Int, errorMessage: String? = "")
31 | }
32 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/BaseHelper.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base
2 |
3 | import com.google.gson.Gson
4 |
5 | /**
6 | * Created by Faisal Amir
7 | * FrogoBox Inc License
8 | * =========================================
9 | * movie
10 | * Copyright (C) 16/11/2019.
11 | * All rights reserved
12 | * -----------------------------------------
13 | * Name : Muhammad Faisal Amir
14 | * E-mail : faisalamircs@gmail.com
15 | * Github : github.com/amirisback
16 | * LinkedIn : linkedin.com/in/faisalamircs
17 | * -----------------------------------------
18 | * FrogoBox Software Industries
19 | * com.frogobox.base
20 | *
21 | */
22 | open class BaseHelper {
23 |
24 | fun baseToJson(model: T) : String? {
25 | return Gson().toJson(model)
26 | }
27 |
28 | inline fun baseFromJson(word: String?) : T {
29 | return Gson().fromJson(word, T::class.java)
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/BaseListener.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base
2 |
3 | /**
4 | * Created by Faisal Amir
5 | * FrogoBox Inc License
6 | * =========================================
7 | * movie
8 | * Copyright (C) 16/11/2019.
9 | * All rights reserved
10 | * -----------------------------------------
11 | * Name : Muhammad Faisal Amir
12 | * E-mail : faisalamircs@gmail.com
13 | * Github : github.com/amirisback
14 | * LinkedIn : linkedin.com/in/faisalamircs
15 | * -----------------------------------------
16 | * FrogoBox Software Industries
17 | * com.frogobox.base
18 | *
19 | */
20 | interface BaseListener {
21 | fun onItemClicked(data: T)
22 | fun onItemLongClicked(data: T)
23 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/BaseViewAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base
2 |
3 | import android.content.Context
4 | import androidx.recyclerview.widget.RecyclerView
5 |
6 | /**
7 | * Created by Faisal Amir
8 | * FrogoBox Inc License
9 | * =========================================
10 | * movie
11 | * Copyright (C) 16/11/2019.
12 | * All rights reserved
13 | * -----------------------------------------
14 | * Name : Muhammad Faisal Amir
15 | * E-mail : faisalamircs@gmail.com
16 | * Github : github.com/amirisback
17 | * LinkedIn : linkedin.com/in/faisalamircs
18 | * -----------------------------------------
19 | * FrogoBox Software Industries
20 | * com.frogobox.base
21 | *
22 | */
23 | abstract class BaseViewAdapter> : RecyclerView.Adapter() {
24 |
25 | protected lateinit var mContext: Context
26 | protected lateinit var mListener: BaseListener
27 |
28 | protected val mRecyclerViewDataList = mutableListOf()
29 | protected var mRecyclerViewLayout: Int = 0
30 |
31 | fun setRecyclerViewLayout(context: Context, layoutItem: Int) {
32 | mContext = context
33 | mRecyclerViewLayout = layoutItem
34 | }
35 |
36 | fun setRecyclerViewListener(listener: BaseListener) {
37 | mListener = listener
38 | }
39 |
40 | fun setRecyclerViewData(dataList: List) {
41 | mRecyclerViewDataList.clear()
42 | mRecyclerViewDataList.addAll(dataList)
43 | notifyDataSetChanged()
44 | }
45 |
46 | fun nukeRecyclerViewData(){
47 | mRecyclerViewDataList.clear()
48 | notifyDataSetChanged()
49 | }
50 |
51 | override fun onBindViewHolder(holder: Holder, position: Int) {
52 | holder.bindItem(mRecyclerViewDataList[position], mListener)
53 | }
54 |
55 | override fun getItemCount(): Int = mRecyclerViewDataList.size
56 |
57 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/BaseViewHolder.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base
2 |
3 | import android.view.View
4 | import androidx.recyclerview.widget.RecyclerView
5 |
6 | /**
7 | * Created by Faisal Amir
8 | * FrogoBox Inc License
9 | * =========================================
10 | * movie
11 | * Copyright (C) 16/11/2019.
12 | * All rights reserved
13 | * -----------------------------------------
14 | * Name : Muhammad Faisal Amir
15 | * E-mail : faisalamircs@gmail.com
16 | * Github : github.com/amirisback
17 | * LinkedIn : linkedin.com/in/faisalamircs
18 | * -----------------------------------------
19 | * FrogoBox Software Industries
20 | * com.frogobox.base
21 | *
22 | */
23 | abstract class BaseViewHolder(view: View) : RecyclerView.ViewHolder(view) {
24 |
25 | open fun bindItem(data: T, listener: BaseListener){
26 | onItemViewClicked(data, listener)
27 | initComponent(data)
28 | }
29 |
30 | protected fun onItemViewClicked(data: T, listener: BaseListener){
31 | itemView.setOnClickListener {
32 | listener.onItemClicked(data)
33 | }
34 | }
35 |
36 | open fun initComponent(data: T){
37 | // component view
38 | }
39 |
40 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.AndroidViewModel
5 | import com.frogobox.base.util.SingleLiveEvent
6 |
7 | /**
8 | * Created by Faisal Amir
9 | * FrogoBox Inc License
10 | * =========================================
11 | * movie
12 | * Copyright (C) 16/11/2019.
13 | * All rights reserved
14 | * -----------------------------------------
15 | * Name : Muhammad Faisal Amir
16 | * E-mail : faisalamircs@gmail.com
17 | * Github : github.com/amirisback
18 | * LinkedIn : linkedin.com/in/faisalamircs
19 | * -----------------------------------------
20 | * FrogoBox Software Industries
21 | * com.frogobox.base
22 | *
23 | */
24 |
25 | open class BaseViewModel(application: Application) : AndroidViewModel(application) {
26 | var eventShowProgress = SingleLiveEvent()
27 | var eventIsEmpty = SingleLiveEvent()
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/adapter/FavoriteMovieAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import com.bumptech.glide.Glide
9 | import com.frogobox.base.BuildConfig
10 | import com.frogobox.base.source.model.FavoriteMovie
11 | import com.frogobox.base.BaseViewAdapter
12 | import com.frogobox.base.BaseViewHolder
13 | import com.frogobox.base.R
14 | import com.frogobox.base.util.Helper
15 |
16 | /**
17 | * Created by Faisal Amir
18 | * FrogoBox Inc License
19 | * =========================================
20 | * movie
21 | * Copyright (C) 16/11/2019.
22 | * All rights reserved
23 | * -----------------------------------------
24 | * Name : Muhammad Faisal Amir
25 | * E-mail : faisalamircs@gmail.com
26 | * Github : github.com/amirisback
27 | * LinkedIn : linkedin.com/in/faisalamircs
28 | * -----------------------------------------
29 | * FrogoBox Software Industries
30 | * com.frogobox.base.adapter
31 | *
32 | */
33 | class FavoriteMovieAdapter :
34 | BaseViewAdapter() {
35 |
36 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavoriteMovieAdapter.FavoriteMovieViewHolder =
37 |
38 | FavoriteMovieViewHolder(
39 | LayoutInflater.from(mContext).inflate(
40 | mRecyclerViewLayout,
41 | parent,
42 | false
43 | )
44 | )
45 |
46 | inner class FavoriteMovieViewHolder(view: View) : BaseViewHolder(view) {
47 |
48 | private val ivPoster = view.findViewById(R.id.iv_poster)
49 | private val tvTitle = view.findViewById(R.id.tv_title)
50 | private val tvOverview = view.findViewById(R.id.tv_overview)
51 |
52 | override fun initComponent(data: FavoriteMovie) {
53 | super.initComponent(data)
54 | val poster = data.poster_path?.let { Helper.Func.removeBackSlash(it) }
55 | Glide.with(mContext).load(BuildConfig.TMDB_PATH_URL_IMAGE + poster).into(ivPoster)
56 | tvTitle.text = data.title
57 | tvOverview.text = data.overview
58 | }
59 |
60 | }
61 |
62 |
63 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/adapter/FavoriteTvShowAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import com.bumptech.glide.Glide
9 | import com.frogobox.base.BuildConfig
10 | import com.frogobox.base.source.model.FavoriteTvShow
11 | import com.frogobox.base.BaseViewAdapter
12 | import com.frogobox.base.BaseViewHolder
13 | import com.frogobox.base.R
14 | import com.frogobox.base.util.Helper
15 |
16 | /**
17 | * Created by Faisal Amir
18 | * FrogoBox Inc License
19 | * =========================================
20 | * movie
21 | * Copyright (C) 16/11/2019.
22 | * All rights reserved
23 | * -----------------------------------------
24 | * Name : Muhammad Faisal Amir
25 | * E-mail : faisalamircs@gmail.com
26 | * Github : github.com/amirisback
27 | * LinkedIn : linkedin.com/in/faisalamircs
28 | * -----------------------------------------
29 | * FrogoBox Software Industries
30 | * com.frogobox.base.adapter
31 | *
32 | */
33 | class FavoriteTvShowAdapter :
34 | BaseViewAdapter() {
35 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavoriteTvShowViewHolder =
36 |
37 | FavoriteTvShowViewHolder(
38 | LayoutInflater.from(mContext).inflate(
39 | mRecyclerViewLayout,
40 | parent,
41 | false
42 | )
43 | )
44 |
45 | inner class FavoriteTvShowViewHolder(view: View) : BaseViewHolder(view) {
46 |
47 | private val ivPoster = view.findViewById(R.id.iv_poster)
48 | private val tvTitle = view.findViewById(R.id.tv_title)
49 | private val tvOverview = view.findViewById(R.id.tv_overview)
50 |
51 | override fun initComponent(data: FavoriteTvShow) {
52 | super.initComponent(data)
53 | val poster = data.poster_path?.let { Helper.Func.removeBackSlash(it) }
54 | Glide.with(mContext).load(BuildConfig.TMDB_PATH_URL_IMAGE + poster).into(ivPoster)
55 | tvTitle.text = data.name
56 | tvOverview.text = data.overview
57 | }
58 |
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/adapter/MovieAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import com.frogobox.base.BuildConfig
9 | import com.frogobox.base.source.model.Movie
10 | import com.frogobox.base.BaseViewAdapter
11 | import com.frogobox.base.BaseViewHolder
12 | import com.frogobox.base.util.Helper.Func.removeBackSlash
13 | import com.bumptech.glide.Glide
14 | import com.frogobox.base.R
15 |
16 | /**
17 | * Created by Faisal Amir
18 | * FrogoBox Inc License
19 | * =========================================
20 | * movie
21 | * Copyright (C) 16/11/2019.
22 | * All rights reserved
23 | * -----------------------------------------
24 | * Name : Muhammad Faisal Amir
25 | * E-mail : faisalamircs@gmail.com
26 | * Github : github.com/amirisback
27 | * LinkedIn : linkedin.com/in/faisalamircs
28 | * -----------------------------------------
29 | * FrogoBox Software Industries
30 | * com.frogobox.base.adapter
31 | *
32 | */
33 | class MovieAdapter :
34 | BaseViewAdapter() {
35 |
36 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
37 | MovieViewHolder(
38 | LayoutInflater.from(mContext).inflate(
39 | mRecyclerViewLayout,
40 | parent,
41 | false
42 | )
43 | )
44 |
45 | inner class MovieViewHolder(view: View) : BaseViewHolder(view) {
46 |
47 | private val ivPoster = view.findViewById(R.id.iv_poster)
48 | private val tvTitle = view.findViewById(R.id.tv_title)
49 | private val tvOverview = view.findViewById(R.id.tv_overview)
50 |
51 | override fun initComponent(data: Movie) {
52 | super.initComponent(data)
53 | val poster = data.poster_path?.let { removeBackSlash(it) }
54 | Glide.with(mContext).load(BuildConfig.TMDB_PATH_URL_IMAGE + poster).into(ivPoster)
55 | tvTitle.text = data.title
56 | tvOverview.text = data.overview
57 | }
58 |
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/adapter/TvShowAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.adapter
2 |
3 | import android.view.LayoutInflater
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import android.widget.ImageView
7 | import android.widget.TextView
8 | import com.frogobox.base.BuildConfig
9 | import com.frogobox.base.source.model.TvShow
10 | import com.frogobox.base.BaseViewAdapter
11 | import com.frogobox.base.BaseViewHolder
12 | import com.frogobox.base.util.Helper
13 | import com.bumptech.glide.Glide
14 | import com.frogobox.base.R
15 |
16 | /**
17 | * Created by Faisal Amir
18 | * FrogoBox Inc License
19 | * =========================================
20 | * movie
21 | * Copyright (C) 16/11/2019.
22 | * All rights reserved
23 | * -----------------------------------------
24 | * Name : Muhammad Faisal Amir
25 | * E-mail : faisalamircs@gmail.com
26 | * Github : github.com/amirisback
27 | * LinkedIn : linkedin.com/in/faisalamircs
28 | * -----------------------------------------
29 | * FrogoBox Software Industries
30 | * com.frogobox.base.adapter
31 | *
32 | */
33 | class TvShowAdapter : BaseViewAdapter() {
34 |
35 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
36 | TvShowViewHolder(
37 | LayoutInflater.from(mContext).inflate(
38 | mRecyclerViewLayout,
39 | parent,
40 | false
41 | )
42 | )
43 |
44 | inner class TvShowViewHolder(view: View) : BaseViewHolder(view) {
45 |
46 | private val ivPoster = view.findViewById(R.id.iv_poster)
47 | private val tvTitle = view.findViewById(R.id.tv_title)
48 | private val tvOverview = view.findViewById(R.id.tv_overview)
49 |
50 | override fun initComponent(data: TvShow) {
51 | super.initComponent(data)
52 | val poster = data.poster_path?.let { Helper.Func.removeBackSlash(it) }
53 | Glide.with(mContext).load(BuildConfig.TMDB_PATH_URL_IMAGE + poster).into(ivPoster)
54 | tvTitle.text = data.name
55 | tvOverview.text = data.overview
56 | }
57 |
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/callback/DeleteViewCallback.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.callback
2 |
3 | /**
4 | * Created by Faisal Amir
5 | * FrogoBox Inc License
6 | * =========================================
7 | * movie
8 | * Copyright (C) 16/11/2019.
9 | * All rights reserved
10 | * -----------------------------------------
11 | * Name : Muhammad Faisal Amir
12 | * E-mail : faisalamircs@gmail.com
13 | * Github : github.com/amirisback
14 | * LinkedIn : linkedin.com/in/faisalamircs
15 | * -----------------------------------------
16 | * FrogoBox Software Industries
17 | * com.frogobox.base.callback
18 | *
19 | */
20 | interface DeleteViewCallback {
21 | fun onShowProgress()
22 | fun onHideProgress()
23 | fun onSuccesDelete()
24 | fun onFailed(message: String)
25 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/callback/SaveViewCallback.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.callback
2 |
3 | /**
4 | * Created by Faisal Amir
5 | * FrogoBox Inc License
6 | * =========================================
7 | * movie
8 | * Copyright (C) 16/11/2019.
9 | * All rights reserved
10 | * -----------------------------------------
11 | * Name : Muhammad Faisal Amir
12 | * E-mail : faisalamircs@gmail.com
13 | * Github : github.com/amirisback
14 | * LinkedIn : linkedin.com/in/faisalamircs
15 | * -----------------------------------------
16 | * FrogoBox Software Industries
17 | * com.frogobox.base.callback
18 | *
19 | */
20 | interface SaveViewCallback {
21 | fun onShowProgress()
22 | fun onHideProgress()
23 | fun onSuccesInsert()
24 | fun onFailed(message: String)
25 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/service/Notification.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.service
2 |
3 | import android.app.NotificationChannel
4 | import android.app.NotificationManager
5 | import android.app.PendingIntent
6 | import android.content.ComponentName
7 | import android.content.Context
8 | import android.content.Intent
9 | import android.graphics.BitmapFactory
10 | import android.media.RingtoneManager
11 | import android.os.Build
12 | import androidx.core.app.NotificationCompat
13 | import com.frogobox.base.R
14 | import com.frogobox.base.util.Constant.Constant.PACKAGE_ROOT
15 | import com.frogobox.base.util.Constant.Constant.PATH_MAIN_ACTIVITY
16 |
17 | /**
18 | * Created by Faisal Amir
19 | * FrogoBox Inc License
20 | * =========================================
21 | * movie
22 | * Copyright (C) 16/11/2019.
23 | * All rights reserved
24 | * -----------------------------------------
25 | * Name : Muhammad Faisal Amir
26 | * E-mail : faisalamircs@gmail.com
27 | * Github : github.com/amirisback
28 | * LinkedIn : linkedin.com/in/faisalamircs
29 | * -----------------------------------------
30 | * FrogoBox Software Industries
31 | * com.frogobox.base.service
32 | *
33 | */
34 | class Notification {
35 |
36 | fun sendNotification(
37 | context: Context,
38 | notificationId: Int,
39 | channelId: String?,
40 | channelName: CharSequence?,
41 | contentTitle: String?,
42 | contentText: String?
43 | ) {
44 |
45 | val intent = Intent(Intent.ACTION_MAIN)
46 | intent.component = ComponentName(PACKAGE_ROOT, PATH_MAIN_ACTIVITY)
47 | val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
48 | val alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
49 |
50 | val mNotificationManager =
51 | context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
52 | val mBuilder = channelId.let {
53 | it?.let { it1 ->
54 | NotificationCompat.Builder(context, it1)
55 | .setContentIntent(pendingIntent)
56 | .setSmallIcon(R.drawable.ic_notification)
57 | .setLargeIcon(
58 | BitmapFactory.decodeResource(
59 | context.resources,
60 | R.drawable.ic_notification
61 | )
62 | )
63 | .setContentTitle(contentTitle)
64 | .setContentText(contentText)
65 | .setSound(alarmSound)
66 | }
67 | }
68 |
69 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
70 | val channel = NotificationChannel(
71 | channelId,
72 | channelName,
73 | NotificationManager.IMPORTANCE_DEFAULT
74 | )
75 | channelId.let { it?.let { it1 -> mBuilder?.setChannelId(it1) } }
76 | mNotificationManager.createNotificationChannel(channel)
77 | }
78 |
79 | val notification = mBuilder?.build()
80 | mNotificationManager.notify(notificationId, notification)
81 |
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/source/DataSource.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.source
2 |
3 | import android.content.Context
4 | import android.database.Cursor
5 | import com.frogobox.base.BaseDataSource
6 | import com.frogobox.base.source.model.FavoriteMovie
7 | import com.frogobox.base.source.model.FavoriteTvShow
8 | import com.frogobox.base.source.model.Movie
9 | import com.frogobox.base.source.model.TvShow
10 |
11 | /**
12 | * Created by Faisal Amir
13 | * FrogoBox Inc License
14 | * =========================================
15 | * movie
16 | * Copyright (C) 16/11/2019.
17 | * All rights reserved
18 | * -----------------------------------------
19 | * Name : Muhammad Faisal Amir
20 | * E-mail : faisalamircs@gmail.com
21 | * Github : github.com/amirisback
22 | * LinkedIn : linkedin.com/in/faisalamircs
23 | * -----------------------------------------
24 | * FrogoBox Software Industries
25 | * com.frogobox.base.source
26 | *
27 | */
28 | interface DataSource : BaseDataSource {
29 |
30 | // API TMDB ------------------------------------------------------------------------------------
31 | // Get
32 | fun getMovies(callback: GetRemoteCallback>)
33 | fun getTvShow(callback: GetRemoteCallback>)
34 |
35 | // Search
36 | fun searchMovies(query: String, callback: GetRemoteCallback>)
37 | fun searchTvShow(query: String, callback: GetRemoteCallback>)
38 |
39 | // Reminder
40 | fun reminderReleaseMovie(
41 | dateGte: String,
42 | dateLte: String,
43 | callback: GetRemoteCallback>
44 | )
45 |
46 | // Room Database -------------------------------------------------------------------------------
47 | // Create
48 | fun saveFavoriteMovie(context: Context, data: FavoriteMovie): Boolean
49 | fun saveFavoriteTvShow(context: Context, data: FavoriteTvShow): Boolean
50 |
51 | // Read
52 | fun getFavoriteMovies(callback: GetLocalCallBack>)
53 | fun getFavoriteTvShows(callback: GetLocalCallBack>)
54 |
55 | fun getFavoriteMovieCursor(context: Context, callback: GetLocalCallBack)
56 | fun getFavoriteTvShowCursor(context: Context, callback: GetLocalCallBack)
57 |
58 | fun getFavoriteMoviewCursorById(context: Context, id: Int, callback: GetLocalCallBack)
59 | fun getFavoriteTvShowCursorById(context: Context, id: Int, callback: GetLocalCallBack)
60 |
61 | // Delete
62 | fun deleteFavoriteMovie(tableId: Int): Boolean
63 | fun deleteFavoriteTvShow(tableId: Int): Boolean
64 |
65 | fun deleteFavoriteMovieProvider(context: Context, tableId: Int): Boolean
66 | fun deleteFavoriteTvShowProvider(context: Context, tableId: Int): Boolean
67 |
68 | // Clear
69 | fun nukeFavoriteMovies(): Boolean
70 | fun nukeFavoriteTvShows(): Boolean
71 |
72 | // Shared Preference ---------------------------------------------------------------------------
73 |
74 | // Create
75 | fun savePrefReleaseReminder(state: Boolean)
76 | fun savePrefDailyReminder(state: Boolean)
77 |
78 | // Read
79 | fun getPrefReleaseReminder(): Boolean
80 | fun getPrefDailyReminder(): Boolean
81 |
82 | // Delete
83 | fun deletePrefReleaseReminder()
84 | fun deletePrefDailyReminder()
85 |
86 | // Callback ------------------------------------------------------------------------------------
87 | interface GetRemoteCallback : BaseDataSource.ResponseCallback
88 | interface GetLocalCallBack : BaseDataSource.ResponseCallback
89 |
90 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/source/local/AppDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.source.local
2 |
3 | import android.content.Context
4 | import androidx.room.Database
5 | import androidx.room.Room
6 | import androidx.room.RoomDatabase
7 | import androidx.room.migration.Migration
8 | import androidx.sqlite.db.SupportSQLiteDatabase
9 | import com.frogobox.base.BuildConfig
10 | import com.frogobox.base.source.local.dao.FavoriteMovieDao
11 | import com.frogobox.base.source.local.dao.FavoriteTvShowDao
12 | import com.frogobox.base.source.model.FavoriteMovie
13 | import com.frogobox.base.source.model.FavoriteTvShow
14 | import com.frogobox.base.util.Constant.RoomDatabase.DATABASE_NAME
15 |
16 | /**
17 | * Created by Faisal Amir
18 | * FrogoBox Inc License
19 | * =========================================
20 | * movie
21 | * Copyright (C) 16/11/2019.
22 | * All rights reserved
23 | * -----------------------------------------
24 | * Name : Muhammad Faisal Amir
25 | * E-mail : faisalamircs@gmail.com
26 | * Github : github.com/amirisback
27 | * LinkedIn : linkedin.com/in/faisalamircs
28 | * -----------------------------------------
29 | * FrogoBox Software Industries
30 | * com.frogobox.base.source.local
31 | *
32 | */
33 | @Database(entities = [
34 | (FavoriteMovie::class),
35 | (FavoriteTvShow::class)
36 | ], version = 1)
37 |
38 |
39 | abstract class AppDatabase : RoomDatabase() {
40 |
41 | abstract fun favoriteMovieDao(): FavoriteMovieDao
42 | abstract fun favoriteTvShowDao(): FavoriteTvShowDao
43 |
44 | companion object {
45 |
46 | @Volatile
47 | private var INSTANCE: AppDatabase? = null
48 |
49 | fun getInstance(context: Context): AppDatabase =
50 | INSTANCE ?: synchronized(this) {
51 | INSTANCE
52 | ?: buildDatabase(context).also {
53 | INSTANCE = it
54 | }
55 | }
56 |
57 | private fun buildDatabase(context: Context): AppDatabase {
58 | return if (BuildConfig.DEBUG) {
59 | Room.databaseBuilder(context.applicationContext,
60 | AppDatabase::class.java, DATABASE_NAME)
61 | .addMigrations(MIGRATION_2_3)
62 | .fallbackToDestructiveMigration() // FOR DEVELOPMENT ONLY !!!!
63 | .build()
64 | } else {
65 | Room.databaseBuilder(context.applicationContext,
66 | AppDatabase::class.java, DATABASE_NAME)
67 | .addMigrations(MIGRATION_2_3)
68 | .build()
69 | }
70 | }
71 |
72 | private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
73 | override fun migrate(database: SupportSQLiteDatabase) {
74 |
75 | }
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/source/local/dao/FavoriteMovieDao.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.source.local.dao
2 |
3 | import android.database.Cursor
4 | import androidx.room.Dao
5 | import androidx.room.Insert
6 | import androidx.room.Query
7 | import com.frogobox.base.source.model.FavoriteMovie
8 | import com.frogobox.base.util.Constant.RoomDatabase.Movie.COLUMN_ID
9 | import com.frogobox.base.util.Constant.RoomDatabase.Movie.TABLE_NAME
10 | import com.frogobox.base.util.Constant.RoomDatabase.Movie._ID
11 | import io.reactivex.rxjava3.core.Single
12 |
13 | /**
14 | * Created by Faisal Amir
15 | * FrogoBox Inc License
16 | * =========================================
17 | * movie
18 | * Copyright (C) 16/11/2019.
19 | * All rights reserved
20 | * -----------------------------------------
21 | * Name : Muhammad Faisal Amir
22 | * E-mail : faisalamircs@gmail.com
23 | * Github : github.com/amirisback
24 | * LinkedIn : linkedin.com/in/faisalamircs
25 | * -----------------------------------------
26 | * FrogoBox Software Industries
27 | * com.frogobox.base.source.local.dao
28 | *
29 | */
30 | @Dao
31 | interface FavoriteMovieDao {
32 |
33 | @Query("SELECT * FROM $TABLE_NAME")
34 | fun getAllData(): Single>
35 |
36 | @Insert
37 | fun insertData(data: FavoriteMovie)
38 |
39 | @Query("DELETE FROM $TABLE_NAME WHERE $COLUMN_ID = :tableId")
40 | fun deleteDataFromTableId(tableId: Int)
41 |
42 | @Query("DELETE FROM $TABLE_NAME ")
43 | fun nukeData()
44 |
45 | // Content Provider ----------------------------------------------------------------------------
46 |
47 | @Query("SELECT * FROM $TABLE_NAME")
48 | fun getCursorAllData() : Cursor
49 |
50 | @Query("SELECT * FROM $TABLE_NAME WHERE $_ID = :id")
51 | fun getCursorById(id : Long) : Cursor
52 |
53 | @Insert
54 | fun insertCursor(data: FavoriteMovie) : Long
55 |
56 | @Query("DELETE FROM $TABLE_NAME WHERE $_ID = :id")
57 | fun deleteById(id: Long): Int
58 |
59 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/source/local/dao/FavoriteTvShowDao.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.source.local.dao
2 |
3 | import android.database.Cursor
4 | import androidx.room.Dao
5 | import androidx.room.Insert
6 | import androidx.room.Query
7 | import com.frogobox.base.source.model.FavoriteTvShow
8 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.COLUMN_ID
9 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.TABLE_NAME
10 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow._ID
11 | import io.reactivex.rxjava3.core.Single
12 |
13 | /**
14 | * Created by Faisal Amir
15 | * FrogoBox Inc License
16 | * =========================================
17 | * movie
18 | * Copyright (C) 16/11/2019.
19 | * All rights reserved
20 | * -----------------------------------------
21 | * Name : Muhammad Faisal Amir
22 | * E-mail : faisalamircs@gmail.com
23 | * Github : github.com/amirisback
24 | * LinkedIn : linkedin.com/in/faisalamircs
25 | * -----------------------------------------
26 | * FrogoBox Software Industries
27 | * com.frogobox.base.source.local.dao
28 | *
29 | */
30 | @Dao
31 | interface FavoriteTvShowDao {
32 |
33 | @Query("SELECT * FROM $TABLE_NAME")
34 | fun getAllData(): Single>
35 |
36 | @Insert
37 | fun insertData(data: FavoriteTvShow)
38 |
39 | @Query("DELETE FROM $TABLE_NAME WHERE $COLUMN_ID = :tableId")
40 | fun deleteDataFromTableId(tableId: Int)
41 |
42 | @Query("DELETE FROM $TABLE_NAME")
43 | fun nukeData()
44 |
45 | // Content Provider ----------------------------------------------------------------------------
46 |
47 | @Query("SELECT * FROM $TABLE_NAME")
48 | fun getCursorAllData(): Cursor
49 |
50 | @Query("SELECT * FROM $TABLE_NAME WHERE $_ID = :id")
51 | fun getCursorById(id: Long): Cursor
52 |
53 | @Insert
54 | fun insertCursor(data: FavoriteTvShow): Long
55 |
56 | @Query("DELETE FROM $TABLE_NAME WHERE $_ID = :id")
57 | fun deleteById(id: Long): Int
58 |
59 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/source/model/FavoriteMovie.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.source.model
2 |
3 | import android.content.ContentValues
4 | import android.os.Parcelable
5 | import androidx.room.ColumnInfo
6 | import androidx.room.Entity
7 | import androidx.room.PrimaryKey
8 | import com.frogobox.base.util.Constant.RoomDatabase.Movie.COLUMN_BACKDROP_PATH
9 | import com.frogobox.base.util.Constant.RoomDatabase.Movie.COLUMN_ID
10 | import com.frogobox.base.util.Constant.RoomDatabase.Movie.COLUMN_OVERVIEW
11 | import com.frogobox.base.util.Constant.RoomDatabase.Movie.COLUMN_POSTER_PATH
12 | import com.frogobox.base.util.Constant.RoomDatabase.Movie.COLUMN_TITLE
13 | import com.frogobox.base.util.Constant.RoomDatabase.Movie.TABLE_NAME
14 | import com.frogobox.base.util.Constant.RoomDatabase.Movie._ID
15 | import kotlinx.parcelize.Parcelize
16 |
17 | /**
18 | * Created by Faisal Amir
19 | * FrogoBox Inc License
20 | * =========================================
21 | * movie
22 | * Copyright (C) 16/11/2019.
23 | * All rights reserved
24 | * -----------------------------------------
25 | * Name : Muhammad Faisal Amir
26 | * E-mail : faisalamircs@gmail.com
27 | * Github : github.com/amirisback
28 | * LinkedIn : linkedin.com/in/faisalamircs
29 | * -----------------------------------------
30 | * FrogoBox Software Industries
31 | * com.frogobox.base.model
32 | *
33 | */
34 | @Entity(tableName = TABLE_NAME)
35 | @Parcelize
36 | data class FavoriteMovie(
37 |
38 | @PrimaryKey(autoGenerate = true)
39 | @ColumnInfo(name = _ID)
40 | var table_id: Int = 0,
41 |
42 | @ColumnInfo(name = COLUMN_ID)
43 | var id: Int? = null,
44 |
45 | @ColumnInfo(name = COLUMN_TITLE)
46 | var title: String? = null,
47 |
48 | @ColumnInfo(name = COLUMN_POSTER_PATH)
49 | var poster_path: String? = null,
50 |
51 | @ColumnInfo(name = COLUMN_BACKDROP_PATH)
52 | var backdrop_path: String? = null,
53 |
54 | @ColumnInfo(name = COLUMN_OVERVIEW)
55 | var overview: String? = null
56 |
57 | ) : Parcelable {
58 |
59 | fun fromContentValues(values: ContentValues): FavoriteMovie {
60 | val favoriteMovie = FavoriteMovie()
61 | if (values.containsKey(COLUMN_ID)) {
62 | favoriteMovie.id = values.getAsInteger(COLUMN_ID)!!
63 | }
64 |
65 | if (values.containsKey(COLUMN_TITLE)) {
66 | favoriteMovie.title = values.getAsString(COLUMN_TITLE)
67 | }
68 |
69 | if (values.containsKey(COLUMN_POSTER_PATH)) {
70 | favoriteMovie.poster_path = values.getAsString(COLUMN_POSTER_PATH)
71 | }
72 |
73 | if (values.containsKey(COLUMN_BACKDROP_PATH)) {
74 | favoriteMovie.backdrop_path = values.getAsString(COLUMN_BACKDROP_PATH)
75 | }
76 |
77 | if (values.containsKey(COLUMN_OVERVIEW)) {
78 | favoriteMovie.overview = values.getAsString(COLUMN_OVERVIEW)
79 | }
80 |
81 | return favoriteMovie
82 | }
83 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/source/model/FavoriteTvShow.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.source.model
2 |
3 | import android.content.ContentValues
4 | import android.os.Parcelable
5 | import androidx.room.ColumnInfo
6 | import androidx.room.Entity
7 | import androidx.room.PrimaryKey
8 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.COLUMN_BACKDROP_PATH
9 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.COLUMN_ID
10 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.COLUMN_NAME
11 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.COLUMN_OVERVIEW
12 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.COLUMN_POSTER_PATH
13 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.TABLE_NAME
14 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow._ID
15 | import kotlinx.parcelize.Parcelize
16 |
17 | /**
18 | * Created by Faisal Amir
19 | * FrogoBox Inc License
20 | * =========================================
21 | * movie
22 | * Copyright (C) 16/11/2019.
23 | * All rights reserved
24 | * -----------------------------------------
25 | * Name : Muhammad Faisal Amir
26 | * E-mail : faisalamircs@gmail.com
27 | * Github : github.com/amirisback
28 | * LinkedIn : linkedin.com/in/faisalamircs
29 | * -----------------------------------------
30 | * FrogoBox Software Industries
31 | * com.frogobox.base.model
32 | *
33 | */
34 | @Entity(tableName = TABLE_NAME)
35 | @Parcelize
36 | data class FavoriteTvShow(
37 |
38 | @PrimaryKey(autoGenerate = true)
39 | @ColumnInfo(name = _ID)
40 | var table_id: Int = 0,
41 |
42 | @ColumnInfo(name = COLUMN_ID)
43 | var id: Int? = null,
44 |
45 | @ColumnInfo(name = COLUMN_NAME)
46 | var name: String? = null,
47 |
48 | @ColumnInfo(name = COLUMN_POSTER_PATH)
49 | var poster_path: String? = null,
50 |
51 | @ColumnInfo(name = COLUMN_BACKDROP_PATH)
52 | var backdrop_path: String? = null,
53 |
54 | @ColumnInfo(name = COLUMN_OVERVIEW)
55 | var overview: String? = null
56 |
57 | ) : Parcelable {
58 |
59 | fun fromContentValues(values: ContentValues): FavoriteTvShow {
60 | val favoriteTvShow = FavoriteTvShow()
61 | if (values.containsKey(COLUMN_ID)) {
62 | favoriteTvShow.id = values.getAsInteger(COLUMN_ID)!!
63 | }
64 |
65 | if (values.containsKey(COLUMN_NAME)) {
66 | favoriteTvShow.name = values.getAsString(COLUMN_NAME)
67 | }
68 |
69 | if (values.containsKey(COLUMN_POSTER_PATH)) {
70 | favoriteTvShow.poster_path = values.getAsString(COLUMN_POSTER_PATH)
71 | }
72 |
73 | if (values.containsKey(COLUMN_BACKDROP_PATH)) {
74 | favoriteTvShow.backdrop_path = values.getAsString(COLUMN_BACKDROP_PATH)
75 | }
76 |
77 | if (values.containsKey(COLUMN_OVERVIEW)) {
78 | favoriteTvShow.overview = values.getAsString(COLUMN_OVERVIEW)
79 | }
80 |
81 | return favoriteTvShow
82 | }
83 |
84 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/source/model/Movie.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.source.model
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | /**
8 | * Created by Faisal Amir
9 | * FrogoBox Inc License
10 | * =========================================
11 | * movie
12 | * Copyright (C) 16/11/2019.
13 | * All rights reserved
14 | * -----------------------------------------
15 | * Name : Muhammad Faisal Amir
16 | * E-mail : faisalamircs@gmail.com
17 | * Github : github.com/amirisback
18 | * LinkedIn : linkedin.com/in/faisalamircs
19 | * -----------------------------------------
20 | * FrogoBox Software Industries
21 | * com.frogobox.base.model
22 | *
23 | */
24 | @Parcelize
25 | data class Movie(
26 |
27 | @SerializedName("id")
28 | var id: Int? = null,
29 |
30 | @SerializedName("title")
31 | var title: String? = null,
32 |
33 | @SerializedName("poster_path")
34 | var poster_path: String? = null,
35 |
36 | @SerializedName("backdrop_path")
37 | var backdrop_path: String? = null,
38 |
39 | @SerializedName("overview")
40 | var overview: String? = null
41 |
42 |
43 | ) : Parcelable
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/source/model/TvShow.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.source.model
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | /**
8 | * Created by Faisal Amir
9 | * FrogoBox Inc License
10 | * =========================================
11 | * movie
12 | * Copyright (C) 16/11/2019.
13 | * All rights reserved
14 | * -----------------------------------------
15 | * Name : Muhammad Faisal Amir
16 | * E-mail : faisalamircs@gmail.com
17 | * Github : github.com/amirisback
18 | * LinkedIn : linkedin.com/in/faisalamircs
19 | * -----------------------------------------
20 | * FrogoBox Software Industries
21 | * com.frogobox.base.model
22 | *
23 | */
24 | @Parcelize
25 | data class TvShow(
26 |
27 | @SerializedName("id")
28 | var id: Int? = null,
29 |
30 | @SerializedName("name")
31 | var name: String? = null,
32 |
33 | @SerializedName("poster_path")
34 | var poster_path: String? = null,
35 |
36 | @SerializedName("backdrop_path")
37 | var backdrop_path: String? = null,
38 |
39 | @SerializedName("overview")
40 | var overview: String? = null
41 |
42 | ) : Parcelable
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/source/remote/ApiCallback.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.source.remote
2 |
3 | import com.frogobox.base.BaseApiModel
4 | import com.google.gson.Gson
5 | import io.reactivex.rxjava3.disposables.Disposable
6 | import io.reactivex.rxjava3.core.Observer
7 | import retrofit2.HttpException
8 | import java.net.SocketTimeoutException
9 | import java.net.UnknownHostException
10 |
11 | /**
12 | * Created by Faisal Amir
13 | * FrogoBox Inc License
14 | * =========================================
15 | * movie
16 | * Copyright (C) 16/11/2019.
17 | * All rights reserved
18 | * -----------------------------------------
19 | * Name : Muhammad Faisal Amir
20 | * E-mail : faisalamircs@gmail.com
21 | * Github : github.com/amirisback
22 | * LinkedIn : linkedin.com/in/faisalamircs
23 | * -----------------------------------------
24 | * FrogoBox Software Industries
25 | * com.frogobox.base.source.remote
26 | *
27 | */
28 | abstract class ApiCallback : Observer {
29 |
30 | abstract fun onSuccess(model: M)
31 |
32 | abstract fun onFailure(code: Int, errorMessage: String)
33 |
34 | abstract fun onFinish()
35 |
36 | override fun onComplete() {
37 | onFinish()
38 | }
39 |
40 | override fun onNext(t: M) {
41 | onSuccess(t)
42 | }
43 |
44 | override fun onSubscribe(d: Disposable) {
45 |
46 | }
47 |
48 | override fun onError(e: Throwable) {
49 | e.printStackTrace()
50 | when (e) {
51 | is HttpException -> {
52 | val code = e.code()
53 | var msg = e.message()
54 | var baseDao: BaseApiModel? = null
55 | try {
56 | val body = e.response()?.errorBody()
57 | baseDao = Gson().fromJson>(body!!.string(), BaseApiModel::class.java)
58 | } catch (exception: Exception) {
59 | onFailure(code, exception.message!!)
60 | }
61 |
62 | when (code) {
63 | 504 -> {
64 | msg = baseDao?.message ?: "Error Response"
65 | }
66 | 502, 404 -> {
67 | msg = baseDao?.message ?: "Error Connect or Resource Not Found"
68 | }
69 | 400 -> {
70 | msg = baseDao?.message ?: "Bad Request"
71 | }
72 | 401 -> {
73 | msg = baseDao?.message ?: "Not Authorized"
74 | }
75 | }
76 |
77 | onFailure(code, msg)
78 | }
79 |
80 | is UnknownHostException -> onFailure(-1, "Telah terjadi kesalahan ketika koneksi ke server: ${e.message}")
81 | is SocketTimeoutException -> onFailure(-1, "Telah terjadi kesalahan ketika koneksi ke server: ${e.message}")
82 | else -> onFailure(-1, e.message ?: "Unknown error occured")
83 | }
84 |
85 | onFinish()
86 | }
87 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/util/AppExecutors.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.util
2 |
3 | import android.os.Handler
4 | import android.os.Looper
5 | import java.util.concurrent.Executor
6 | import java.util.concurrent.Executors
7 |
8 | /**
9 | * Created by Faisal Amir
10 | * FrogoBox Inc License
11 | * =========================================
12 | * movie
13 | * Copyright (C) 16/11/2019.
14 | * All rights reserved
15 | * -----------------------------------------
16 | * Name : Muhammad Faisal Amir
17 | * E-mail : faisalamircs@gmail.com
18 | * Github : github.com/amirisback
19 | * LinkedIn : linkedin.com/in/faisalamircs
20 | * -----------------------------------------
21 | * FrogoBox Software Industries
22 | * com.frogobox.base.util
23 | *
24 | */
25 | open class AppExecutors constructor(
26 | val diskIO: Executor = DiskIOThreadExecutor(),
27 | val networkIO: Executor = Executors.newFixedThreadPool(3),
28 | val mainThread: Executor = MainThreadExecutor()
29 | ) {
30 |
31 | private class MainThreadExecutor : Executor {
32 | private val mainThreadHandler = Handler(Looper.getMainLooper())
33 |
34 | override fun execute(command: Runnable) {
35 | mainThreadHandler.post(command)
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/util/DiskIOThreadExecutor.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.util
2 |
3 | import java.util.concurrent.Executor
4 | import java.util.concurrent.Executors
5 |
6 | /**
7 | * Created by Faisal Amir
8 | * FrogoBox Inc License
9 | * =========================================
10 | * movie
11 | * Copyright (C) 16/11/2019.
12 | * All rights reserved
13 | * -----------------------------------------
14 | * Name : Muhammad Faisal Amir
15 | * E-mail : faisalamircs@gmail.com
16 | * Github : github.com/amirisback
17 | * LinkedIn : linkedin.com/in/faisalamircs
18 | * -----------------------------------------
19 | * FrogoBox Software Industries
20 | * com.frogobox.base.util
21 | *
22 | */
23 | class DiskIOThreadExecutor: Executor {
24 |
25 | private val diskIO = Executors.newSingleThreadExecutor()
26 |
27 | override fun execute(command: Runnable) {
28 | diskIO.execute(command)
29 | }
30 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/util/Injection.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.util
2 |
3 | import android.content.Context
4 | import android.preference.PreferenceManager
5 | import com.frogobox.base.source.Repository
6 | import com.frogobox.base.source.local.AppDatabase
7 | import com.frogobox.base.source.local.LocalDataSource
8 | import com.frogobox.base.source.local.dao.FavoriteMovieDao
9 | import com.frogobox.base.source.local.dao.FavoriteTvShowDao
10 | import com.frogobox.base.source.remote.RemoteDataSource
11 |
12 | /**
13 | * Created by Faisal Amir
14 | * FrogoBox Inc License
15 | * =========================================
16 | * movie
17 | * Copyright (C) 16/11/2019.
18 | * All rights reserved
19 | * -----------------------------------------
20 | * Name : Muhammad Faisal Amir
21 | * E-mail : faisalamircs@gmail.com
22 | * Github : github.com/amirisback
23 | * LinkedIn : linkedin.com/in/faisalamircs
24 | * -----------------------------------------
25 | * FrogoBox Software Industries
26 | * com.frogobox.base.util
27 | *
28 | */
29 | object Injection {
30 |
31 | fun provideRepository(context: Context): Repository {
32 |
33 | val favoriteMovieDao: FavoriteMovieDao by lazy {
34 | AppDatabase.getInstance(context).favoriteMovieDao()
35 | }
36 |
37 | val favoriteTvShowDao: FavoriteTvShowDao by lazy {
38 | AppDatabase.getInstance(context).favoriteTvShowDao()
39 | }
40 |
41 | val appExecutors = AppExecutors()
42 |
43 | return Repository.getInstance(
44 | RemoteDataSource, LocalDataSource.getInstance(
45 | appExecutors,
46 | PreferenceManager.getDefaultSharedPreferences(context),
47 | favoriteMovieDao, favoriteTvShowDao))
48 | }
49 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/util/NullAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.util
2 |
3 | import com.google.gson.TypeAdapter
4 | import com.google.gson.stream.JsonReader
5 | import com.google.gson.stream.JsonWriter
6 | import java.io.IOException
7 | import java.lang.reflect.Field
8 | import java.lang.reflect.InvocationTargetException
9 |
10 | /**
11 | * Created by Faisal Amir
12 | * FrogoBox Inc License
13 | * =========================================
14 | * movie
15 | * Copyright (C) 16/11/2019.
16 | * All rights reserved
17 | * -----------------------------------------
18 | * Name : Muhammad Faisal Amir
19 | * E-mail : faisalamircs@gmail.com
20 | * Github : github.com/amirisback
21 | * LinkedIn : linkedin.com/in/faisalamircs
22 | * -----------------------------------------
23 | * FrogoBox Software Industries
24 | * com.frogobox.base.util
25 | *
26 | */
27 | class NullAdapter : TypeAdapter() {
28 | @Throws(IOException::class)
29 | override fun write(jsonWriter: JsonWriter, o: Any) {
30 | jsonWriter.beginObject()
31 | for (field in o.javaClass.declaredFields) {
32 | val fieldValue = runGetter(field, o)
33 | jsonWriter.name(field.name)
34 | if (fieldValue == null) {
35 | jsonWriter.value("")
36 | } else {
37 | jsonWriter.value(fieldValue.toString())
38 | }
39 | }
40 | jsonWriter.endObject()
41 | }
42 |
43 | @Throws(IOException::class)
44 | override fun read(jsonReader: JsonReader): Any? {
45 | /* Don't forget to add implementation here to have your Object back alive :) */
46 | return null
47 | }
48 |
49 | companion object {
50 | /**
51 | * A generic field accessor runner.
52 | * Run the right getter on the field to get its value.
53 | * @param field
54 | * @param o `Object`
55 | * @return
56 | */
57 | fun runGetter(field: Field, o: Any): Any? {
58 | // MZ: Find the correct method
59 | for (method in o.javaClass.methods) {
60 | if (method.name.startsWith("get") && method.name.length == field.name.length + 3) {
61 | if (method.name.toLowerCase().endsWith(field.name.toLowerCase())) {
62 | try {
63 | return method.invoke(o)
64 | } catch (e: IllegalAccessException) {
65 | e.printStackTrace()
66 | } catch (e: InvocationTargetException) {
67 | e.printStackTrace()
68 | }
69 | }
70 | }
71 | }
72 | return null
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/util/PagerHelper.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.util
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.fragment.app.FragmentManager
5 | import androidx.fragment.app.FragmentPagerAdapter
6 |
7 | /**
8 | * Created by Faisal Amir
9 | * FrogoBox Inc License
10 | * =========================================
11 | * movie
12 | * Copyright (C) 16/11/2019.
13 | * All rights reserved
14 | * -----------------------------------------
15 | * Name : Muhammad Faisal Amir
16 | * E-mail : faisalamircs@gmail.com
17 | * Github : github.com/amirisback
18 | * LinkedIn : linkedin.com/in/faisalamircs
19 | * -----------------------------------------
20 | * FrogoBox Software Industries
21 | * com.frogobox.base.util
22 | *
23 | */
24 | @Suppress("DEPRECATION")
25 | class PagerHelper(fragmentManager: FragmentManager): FragmentPagerAdapter(fragmentManager){
26 |
27 | private val fragments = ArrayList()
28 | private val titles = ArrayList()
29 |
30 | override fun getItem(position: Int): Fragment = fragments[position]
31 |
32 | override fun getCount(): Int = fragments.size
33 |
34 | override fun getPageTitle(position: Int): CharSequence? = titles[position]
35 |
36 | fun setupPagerFragment(fragment: Fragment, title: String) {
37 | fragments.add(fragment)
38 | titles.add(title)
39 | }
40 | }
--------------------------------------------------------------------------------
/base/src/main/java/com/frogobox/base/util/SingleLiveEvent.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.base.util
2 |
3 | import android.util.Log
4 | import androidx.annotation.MainThread
5 | import androidx.lifecycle.LifecycleOwner
6 | import androidx.lifecycle.MutableLiveData
7 | import androidx.lifecycle.Observer
8 | import java.util.concurrent.atomic.AtomicBoolean
9 |
10 | /**
11 | * Created by Faisal Amir
12 | * FrogoBox Inc License
13 | * =========================================
14 | * movie
15 | * Copyright (C) 16/11/2019.
16 | * All rights reserved
17 | * -----------------------------------------
18 | * Name : Muhammad Faisal Amir
19 | * E-mail : faisalamircs@gmail.com
20 | * Github : github.com/amirisback
21 | * LinkedIn : linkedin.com/in/faisalamircs
22 | * -----------------------------------------
23 | * FrogoBox Software Industries
24 | * com.frogobox.base.util
25 | *
26 | */
27 | class SingleLiveEvent : MutableLiveData() {
28 |
29 | private val pending = AtomicBoolean(false)
30 |
31 | @MainThread
32 | override fun observe(owner: LifecycleOwner, observer: Observer) {
33 |
34 | if (hasActiveObservers()) {
35 | Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
36 | }
37 |
38 | // Observe the internal MutableLiveData
39 | super.observe(owner, Observer { t ->
40 | if (pending.compareAndSet(true, false)) {
41 | observer.onChanged(t)
42 | }
43 | })
44 | }
45 |
46 | @MainThread
47 | override fun setValue(t: T?) {
48 | pending.set(true)
49 | super.setValue(t)
50 | }
51 |
52 | /**
53 | * Used for cases where T is Void, to make calls cleaner.
54 | */
55 | @MainThread
56 | fun call() {
57 | value = null
58 | }
59 |
60 | companion object {
61 | private const val TAG = "SingleLiveEvent"
62 | }
63 | }
--------------------------------------------------------------------------------
/base/src/main/res/drawable/background_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_arrow_back.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_close.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_favorite.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_movie.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_notification.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_translate.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_tv.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/base/src/main/res/drawable/ic_un_favorite.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/base/src/main/res/layout/activity_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
18 |
34 |
35 |
50 |
51 |
--------------------------------------------------------------------------------
/base/src/main/res/layout/empty_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
24 |
25 |
--------------------------------------------------------------------------------
/base/src/main/res/layout/item_grid_tv_movie.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
23 |
24 |
36 |
37 |
46 |
--------------------------------------------------------------------------------
/base/src/main/res/layout/item_list_tv_movie.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
22 |
23 |
35 |
36 |
47 |
--------------------------------------------------------------------------------
/base/src/main/res/menu/bottom_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/base/src/main/res/menu/toolbar_favorite.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/base/src/main/res/menu/toolbar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/base/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
21 |
22 | #720d5d
23 | #430033
24 | #FF9800
25 |
26 |
27 | #FFFFFF
28 | #000000
29 | #FF0000
30 | #757575
31 |
32 | #E9E7E7
33 |
34 |
--------------------------------------------------------------------------------
/base/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
20 |
21 | 8dp
22 | 16dp
23 |
--------------------------------------------------------------------------------
/base/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Base
3 |
4 | Movie
5 | TV
6 | Setting
7 | Favorite Movie
8 | Favorite TV Show
9 | Favorite
10 |
11 | Detail Movie
12 | Detail TV Show
13 | Search
14 |
15 | Empty Data
16 |
17 | Success add to favorite
18 | Success delete from favorite
19 |
20 | Release Reminder
21 | Reminder showing the movie that released today
22 | Daily Reminder
23 | Reminder for return to app
24 | Select Language
25 |
26 | Don\'t Forget Check Film Today
27 | I miss you
28 | New Movies!
29 | has been release today!
30 |
31 |
32 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id("com.android.application") version "7.1.2" apply false
4 | id("com.android.library") version "7.1.2" apply false
5 | id("org.jetbrains.kotlin.android") version DependencyGradle.KOTLIN_VERSION apply false
6 | }
7 |
8 | tasks.register("clean", Delete::class) {
9 | delete(rootProject.buildDir)
10 | }
--------------------------------------------------------------------------------
/buildSrc/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | .gradle
3 |
--------------------------------------------------------------------------------
/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.gradle.kotlin.dsl.`kotlin-dsl`
2 |
3 | plugins {
4 | `kotlin-dsl`
5 | }
6 |
7 | repositories {
8 | mavenCentral()
9 | maven { url = uri("https://jitpack.io") }
10 | }
11 |
12 | dependencies{
13 | // library open-build-src
14 | implementation("com.github.frogobox:open-build-src:1.0.2")
15 |
16 | // library frogo-build-src
17 | implementation("com.github.frogobox:frogo-build-src:1.0.4")
18 |
19 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/AdmobValue.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Created by faisalamir on 12/03/22
3 | * movie
4 | * -----------------------------------------
5 | * Name : Muhammad Faisal Amir
6 | * E-mail : faisalamircs@gmail.com
7 | * Github : github.com/amirisback
8 | * -----------------------------------------
9 | * Copyright (C) 2022 Frogobox Media Inc.
10 | * All rights reserved
11 | *
12 | */
13 |
14 | object AdmobValue {
15 | // Declaration admob id for debug
16 | const val debugAdmobAppId = "ca-app-pub-3940256099942544~3347511713"
17 | const val debugAdmobBanner = "ca-app-pub-3940256099942544/6300978111"
18 | const val debugAdmobInterstitial = "ca-app-pub-3940256099942544/1033173712"
19 | const val debugAdmobInterstitialVideo = "ca-app-pub-3940256099942544/8691691433"
20 | const val debugAdmobRewarded = "ca-app-pub-3940256099942544/5224354917"
21 | const val debugAdmobRewardedInterstitial = "ca-app-pub-3940256099942544/5354046379"
22 | const val debugAdmobNativeAdvanced = "ca-app-pub-3940256099942544/2247696110"
23 | const val debugAdmobNativeAdvancedVideo = "ca-app-pub-3940256099942544/1044960115"
24 |
25 | // Declaration admob id for release
26 | const val releaseAdmobAppId = "ca-app-pub-3940256099942544~3347511713"
27 | const val releaseAdmobBanner = "ca-app-pub-3940256099942544/6300978111"
28 | const val releaseAdmobInterstitial = "ca-app-pub-3940256099942544/1033173712"
29 | const val releaseAdmobInterstitialVideo = "ca-app-pub-3940256099942544/8691691433"
30 | const val releaseAdmobRewarded = "ca-app-pub-3940256099942544/5224354917"
31 | const val releaseAdmobRewardedInterstitial = "ca-app-pub-3940256099942544/5354046379"
32 | const val releaseAdmobNativeAdvanced = "ca-app-pub-3940256099942544/2247696110"
33 | const val releaseAdmobNativeAdvancedVideo = "ca-app-pub-3940256099942544/1044960115"
34 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/BuildConstant.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Created by faisalamir on 19/09/21
3 | * FrogoRecyclerView
4 | * -----------------------------------------
5 | * Name : Muhammad Faisal Amir
6 | * E-mail : faisalamircs@gmail.com
7 | * Github : github.com/amirisback
8 | * -----------------------------------------
9 | * Copyright (C) 2021 FrogoBox Inc.
10 | * All rights reserved
11 | *
12 | */
13 |
14 | object BuildConstant {
15 |
16 | val TMDB_API_KEY = "\"5e922c3d4b1b0e96fffcc6b0b395878f\""
17 | val TMDB_BASE_URL = "\"https://api.themoviedb.org/\""
18 | val TMDB_BASE_LANG = "\"en-US\""
19 |
20 | val TMDB_PATH_URL_IMAGE = "\"https://image.tmdb.org/t/p/w342/\""
21 |
22 | val TMDB_URL_MOVIE = "\"3/discover/movie?api_key=5e922c3d4b1b0e96fffcc6b0b395878f&language=en-US\""
23 | val TMDB_URL_TV = "\"3/discover/tv?api_key=5e922c3d4b1b0e96fffcc6b0b395878f&language=en-US\""
24 |
25 | val TMDB_URL_SEARCH_MOVIE = "\"3/search/movie\""
26 | val TMDB_URL_SEARCH_TV_SHOW = "\"3/search/tv\""
27 |
28 | val TMDB_URL_RELEASE_BY_DATE = "\"3/discover/movie?api_key={API KEY}&primary_release_date.gte={TODAY DATE}&primary_release_date.lte={TODAY DATE}\""
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/DependencyGradle.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Created by faisalamir on 19/09/21
3 | * FrogoRecyclerView
4 | * -----------------------------------------
5 | * Name : Muhammad Faisal Amir
6 | * E-mail : faisalamircs@gmail.com
7 | * Github : github.com/amirisback
8 | * -----------------------------------------
9 | * Copyright (C) 2021 FrogoBox Inc.
10 | * All rights reserved
11 | *
12 | */
13 |
14 | object DependencyGradle {
15 |
16 | const val KOTLIN_VERSION = Version.JetBrains.kotlin
17 | const val COMPOSE_MULTIPLATFORM_VERSION = Version.AndroidX.composeMultiPlatform
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/ProjectSetting.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Created by faisalamir on 19/09/21
3 | * FrogoRecyclerView
4 | * -----------------------------------------
5 | * Name : Muhammad Faisal Amir
6 | * E-mail : faisalamircs@gmail.com
7 | * Github : github.com/amirisback
8 | * -----------------------------------------
9 | * Copyright (C) 2021 FrogoBox Inc.
10 | * All rights reserved
11 | *
12 | */
13 |
14 | object ProjectSetting {
15 |
16 | const val NAME_APP = "FrogoKickStartAndroid"
17 |
18 | const val APP_DOMAIN = "com"
19 | const val APP_PLAY_CONSOLE = "frogobox"
20 | const val APP_NAME = "movie"
21 |
22 | const val APP_NAME_FAV = "favorite"
23 |
24 | const val LIBRARY_NAME_BASE = "base"
25 |
26 | const val MODULE_NAME_SDK = "base"
27 |
28 | // ---------------------------------------------------------------------------------------------
29 |
30 | const val VERSION_MAJOR = 1
31 | const val VERSION_MINOR = 0
32 | const val VERSION_PATCH = 0
33 |
34 | // ---------------------------------------------------------------------------------------------
35 |
36 | const val PROJECT_MIN_SDK = 21
37 | const val PROJECT_COMPILE_SDK = 31
38 | const val PROJECT_TARGET_SDK = PROJECT_COMPILE_SDK
39 |
40 | // ---------------------------------------------------------------------------------------------
41 |
42 | const val BASE_PACAKGE_NAME = "$APP_DOMAIN.$APP_PLAY_CONSOLE"
43 |
44 | const val PROJECT_APP_ID = "$BASE_PACAKGE_NAME.$APP_NAME"
45 | const val PROJECT_APP_FAV_ID = "$BASE_PACAKGE_NAME.$APP_NAME_FAV"
46 | const val PROJECT_LIB_ID_BASE = "$BASE_PACAKGE_NAME.$LIBRARY_NAME_BASE"
47 |
48 | const val PROJECT_VERSION_CODE = (VERSION_MAJOR * 100) + (VERSION_MINOR * 10) + (VERSION_PATCH * 1)
49 | const val PROJECT_VERSION_NAME = "$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH"
50 |
51 | val NAME_APK = NAME_APP.toLowerCase().replace(" ", "-")
52 |
53 | val NAME_DB = NAME_APP.toLowerCase().replace(" ", "_")
54 | val DB = "\"$NAME_DB.db\""
55 |
56 | // ---------------------------------------------------------------------------------------------
57 |
58 | const val PLAYSTORE_STORE_FILE = "frogoboxmedia.jks"
59 | const val PLAYSTORE_STORE_PASSWORD = "amirisback"
60 | const val PLAYSTORE_KEY_ALIAS = "frogoisback"
61 | const val PLAYSTORE_KEY_PASSWORD = "amirisback"
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/docs/image/mad_score.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/docs/image/mad_score.png
--------------------------------------------------------------------------------
/docs/image/ss_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/docs/image/ss_1.png
--------------------------------------------------------------------------------
/docs/image/ss_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/docs/image/ss_2.png
--------------------------------------------------------------------------------
/docs/image/ss_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/docs/image/ss_3.png
--------------------------------------------------------------------------------
/docs/image/ss_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/docs/image/ss_banner.png
--------------------------------------------------------------------------------
/docs/image/ss_play_store.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/docs/image/ss_play_store.jpg
--------------------------------------------------------------------------------
/favorite/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/favorite/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.android.application")
3 | id("org.jetbrains.kotlin.android")
4 | id("kotlin-kapt")
5 | id("kotlin-parcelize")
6 | }
7 |
8 | android {
9 |
10 | compileSdk = ProjectSetting.PROJECT_COMPILE_SDK
11 |
12 | defaultConfig {
13 | applicationId = ProjectSetting.PROJECT_APP_FAV_ID
14 | minSdk = ProjectSetting.PROJECT_MIN_SDK
15 | targetSdk = ProjectSetting.PROJECT_TARGET_SDK
16 | versionCode = ProjectSetting.PROJECT_VERSION_CODE
17 | versionName = ProjectSetting.PROJECT_VERSION_NAME
18 |
19 | multiDexEnabled = true
20 | vectorDrawables.useSupportLibrary = true
21 |
22 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
23 |
24 | // Naming APK // AAB
25 | setProperty("archivesBaseName", "${ProjectSetting.NAME_APK}(${versionName})")
26 |
27 | // Declaration apps name debug mode
28 | val debugAttribute = "Development"
29 | val nameAppDebug = "${ProjectSetting.NAME_APP} $debugAttribute"
30 | resourceConfigurations += setOf("en", "id")
31 |
32 | // Inject app name for debug
33 | resValue("string", "app_name", nameAppDebug)
34 |
35 |
36 | }
37 |
38 | buildTypes {
39 | getByName("release") {
40 | isMinifyEnabled = false
41 |
42 | proguardFiles(
43 | getDefaultProguardFile("proguard-android-optimize.txt"),
44 | "proguard-rules.pro"
45 | )
46 | }
47 | }
48 |
49 | buildFeatures {
50 | viewBinding = true
51 | }
52 |
53 | compileOptions {
54 | sourceCompatibility = JavaVersion.VERSION_11
55 | targetCompatibility = JavaVersion.VERSION_11
56 | }
57 |
58 | tasks.withType {
59 | kotlinOptions {
60 | jvmTarget = JavaVersion.VERSION_11.toString()
61 | }
62 | }
63 |
64 | }
65 |
66 | dependencies {
67 |
68 | implementation(project(":base"))
69 |
70 | implementation(Androidx.appCompat)
71 | implementation(Androidx.Core.ktx)
72 | implementation(Androidx.constraintLayout)
73 | implementation(Androidx.preferenceKtx)
74 |
75 | implementation(Androidx.Lifecycle.viewmodelKtx)
76 | implementation(Androidx.Work.runtimeKtx)
77 |
78 | implementation(Androidx.Room.runtime)
79 | implementation(Androidx.Room.ktx)
80 | implementation(Androidx.Room.rxJava3)
81 |
82 | implementation(Google.gson)
83 | implementation(Google.material)
84 |
85 | implementation(Square.okhttp)
86 | implementation(Square.okhttpLogging)
87 | implementation(Square.Retrofit2.retrofit)
88 | implementation(Square.Retrofit2.converterGson)
89 | implementation(Square.Retrofit2.adapterRxJava3)
90 |
91 | implementation(Reactivex.rxJava3)
92 | implementation(Reactivex.rxAndroid3)
93 |
94 | implementation(Util.glide)
95 |
96 | implementation(Frogo.ui)
97 | implementation(Frogo.recyclerView)
98 |
99 | implementation(Koin.core)
100 | implementation(Koin.android)
101 | implementation(Koin.androidCompat)
102 | implementation(Koin.androidxWorkManager)
103 | implementation(Koin.androidxCompose)
104 |
105 | api("com.google.dagger:dagger:2.38.1")
106 | api(JetBrains.coroutinesCore)
107 | api(JetBrains.coroutinesAndroid)
108 |
109 | kapt(Androidx.Lifecycle.compiler)
110 | kapt(Androidx.Room.compiler)
111 | kapt(Util.glideCompiler)
112 | kapt("com.google.dagger:dagger-compiler:2.37")
113 |
114 | testImplementation("junit:junit:4.13.2")
115 | testImplementation("androidx.room:room-testing:2.4.2")
116 |
117 | androidTestImplementation("androidx.room:room-testing:2.4.2")
118 | androidTestImplementation("androidx.arch.core:core-testing:2.1.0")
119 | androidTestImplementation("androidx.test:runner:1.4.0")
120 | androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
121 |
122 | }
--------------------------------------------------------------------------------
/favorite/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/favorite/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/favorite/src/main/java/com/frogobox/favorite/mvvm/main/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.favorite.mvvm.main
2 |
3 | import android.os.Bundle
4 | import com.frogobox.base.util.PagerHelper
5 | import com.frogobox.favorite.R
6 | import com.frogobox.favorite.databinding.ActivityMainBinding
7 | import com.frogobox.favorite.mvvm.movie.MovieFragment
8 | import com.frogobox.favorite.mvvm.tv.TvShowFragment
9 | import com.frogobox.favorite.util.BaseFavoriteActivity
10 | import com.frogobox.favorite.mvvm.movie.MovieViewModel
11 | import com.frogobox.favorite.mvvm.tv.TvShowViewModel
12 |
13 | class MainActivity : BaseFavoriteActivity() {
14 |
15 | override fun setupViewBinding(): ActivityMainBinding {
16 | return ActivityMainBinding.inflate(layoutInflater)
17 | }
18 |
19 | override fun setupViewModel() {}
20 |
21 | override fun setupUI(savedInstanceState: Bundle?) {
22 | mActivity.title = getString(R.string.title_favorite)
23 | setupViewPager()
24 | }
25 |
26 | fun obtainMovieViewModel(): MovieViewModel =
27 | obtainViewModel(MovieViewModel::class.java)
28 |
29 | fun obtainTvShowViewModel(): TvShowViewModel =
30 | obtainViewModel(TvShowViewModel::class.java)
31 |
32 | private fun setupViewPager() {
33 | val pagerAdapter = PagerHelper(supportFragmentManager)
34 | pagerAdapter.setupPagerFragment(
35 | MovieFragment(),
36 | resources.getString(R.string.title_favorite_movie)
37 | )
38 | pagerAdapter.setupPagerFragment(
39 | TvShowFragment(),
40 | resources.getString(R.string.title_favorite_tv_show)
41 | )
42 | binding.apply {
43 | viewpager.adapter = pagerAdapter
44 | tablayout.setupWithViewPager(viewpager)
45 | }
46 | }
47 |
48 | }
--------------------------------------------------------------------------------
/favorite/src/main/java/com/frogobox/favorite/mvvm/movie/MovieFragment.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.favorite.mvvm.movie
2 |
3 |
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.ViewGroup
7 | import androidx.fragment.app.Fragment
8 | import androidx.lifecycle.Observer
9 | import androidx.recyclerview.widget.LinearLayoutManager
10 | import com.frogobox.base.BaseFragment
11 | import com.frogobox.base.BaseListener
12 | import com.frogobox.base.source.model.FavoriteMovie
13 | import com.frogobox.favorite.R
14 | import com.frogobox.favorite.databinding.FragmentTvMovieListBinding
15 | import com.frogobox.favorite.mvvm.main.MainActivity
16 |
17 | /**
18 | * A simple [Fragment] subclass.
19 | */
20 | class MovieFragment : BaseFragment(),
21 | BaseListener {
22 |
23 | private lateinit var mViewModel: MovieViewModel
24 |
25 | override fun setupViewBinding(
26 | inflater: LayoutInflater,
27 | container: ViewGroup
28 | ): FragmentTvMovieListBinding {
29 | return FragmentTvMovieListBinding.inflate(inflater, container, false)
30 | }
31 |
32 | override fun setupViewModel() {
33 | mViewModel = (activity as MainActivity).obtainMovieViewModel().apply {
34 |
35 | favMovieListLive.observe(viewLifecycleOwner) {
36 | setupRecyclerView(it)
37 | }
38 |
39 | eventShowProgress.observe(viewLifecycleOwner) {
40 | setupEventProgressView(binding?.progressBar!!, it)
41 | }
42 |
43 | eventIsEmpty.observe(viewLifecycleOwner) {
44 | // setupEventEmptyView(empty_view, it)
45 | }
46 |
47 | }
48 | }
49 |
50 | override fun setupUI(savedInstanceState: Bundle?) {
51 | getMovie()
52 | }
53 |
54 | override fun onResume() {
55 | super.onResume()
56 | getMovie()
57 | }
58 |
59 | private fun getMovie() {
60 | mViewModel.getFavoriteMovie()
61 | }
62 |
63 | private fun setupRecyclerView(data: List) {
64 | val adapter = com.frogobox.base.adapter.FavoriteMovieAdapter()
65 | context?.let { adapter.setRecyclerViewLayout(it, R.layout.item_list_tv_movie) }
66 | adapter.setRecyclerViewListener(this)
67 | adapter.setRecyclerViewData(data)
68 | binding?.apply {
69 | recyclerView.adapter = adapter
70 | recyclerView.layoutManager =
71 | LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
72 | }
73 | }
74 |
75 | override fun onItemClicked(data: FavoriteMovie) {
76 | context?.let {
77 | baseStartActivity(
78 | it,
79 | DetailMovieActivity.EXTRA_FAV_MOVIE,
80 | data
81 | )
82 | }
83 | }
84 |
85 | override fun onItemLongClicked(data: FavoriteMovie) {}
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/favorite/src/main/java/com/frogobox/favorite/mvvm/movie/MovieViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.favorite.mvvm.movie
2 |
3 | import android.app.Application
4 | import android.database.Cursor
5 | import com.frogobox.base.BaseViewModel
6 | import com.frogobox.base.source.model.FavoriteMovie
7 | import com.frogobox.base.source.DataSource
8 | import com.frogobox.base.source.Repository
9 | import com.frogobox.base.util.Constant.RoomDatabase.Movie.setupCursor
10 | import com.frogobox.base.util.SingleLiveEvent
11 |
12 | /**
13 | * Created by Faisal Amir
14 | * FrogoBox Inc License
15 | * =========================================
16 | * movie
17 | * Copyright (C) 16/11/2019.
18 | * All rights reserved
19 | * -----------------------------------------
20 | * Name : Muhammad Faisal Amir
21 | * E-mail : faisalamircs@gmail.com
22 | * Github : github.com/amirisback
23 | * LinkedIn : linkedin.com/in/faisalamircs
24 | * -----------------------------------------
25 | * FrogoBox Software Industries
26 | * com.frogobox.favorite
27 | *
28 | */
29 | class MovieViewModel(private val context: Application, private val repository: Repository) :
30 | BaseViewModel(context) {
31 |
32 | var favMovieListLive = SingleLiveEvent>()
33 |
34 | fun getFavoriteMovie() {
35 | repository.getFavoriteMovieCursor(context, object :
36 | DataSource.GetLocalCallBack {
37 | override fun onShowProgressDialog() {
38 | eventShowProgress.postValue(true)
39 | }
40 |
41 | override fun onHideProgressDialog() {
42 | eventShowProgress.postValue(false)
43 | }
44 |
45 | override fun onSuccess(data: Cursor) {
46 | favMovieListLive.postValue(setupCursor(data))
47 | eventIsEmpty.postValue(false)
48 | }
49 |
50 | override fun onFinish() {
51 |
52 | }
53 |
54 | override fun onEmpty() {
55 | eventIsEmpty.postValue(true)
56 | }
57 |
58 | override fun onFailed(statusCode: Int, errorMessage: String?) {
59 |
60 | }
61 | })
62 | }
63 |
64 |
65 | }
--------------------------------------------------------------------------------
/favorite/src/main/java/com/frogobox/favorite/mvvm/tv/DetailTvShowViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.favorite.mvvm.tv
2 |
3 | import android.app.Application
4 | import android.database.Cursor
5 | import com.frogobox.base.BaseViewModel
6 | import com.frogobox.base.source.DataSource
7 | import com.frogobox.base.source.Repository
8 | import com.frogobox.base.source.model.FavoriteTvShow
9 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.setupCursor
10 | import com.frogobox.base.util.SingleLiveEvent
11 |
12 | /**
13 | * Created by Faisal Amir
14 | * FrogoBox Inc License
15 | * =========================================
16 | * movie
17 | * Copyright (C) 16/11/2019.
18 | * All rights reserved
19 | * -----------------------------------------
20 | * Name : Muhammad Faisal Amir
21 | * E-mail : faisalamircs@gmail.com
22 | * Github : github.com/amirisback
23 | * LinkedIn : linkedin.com/in/faisalamircs
24 | * -----------------------------------------
25 | * FrogoBox Software Industries
26 | * com.frogobox.favorite
27 | *
28 | */
29 | class DetailTvShowViewModel(private val context: Application, private val repository: Repository) :
30 | BaseViewModel(context) {
31 |
32 | var favoriteTvShow = SingleLiveEvent()
33 | var eventIsFavorite = SingleLiveEvent()
34 |
35 | fun saveFavoriteTvShow(
36 | data: FavoriteTvShow,
37 | callback: com.frogobox.base.callback.SaveViewCallback
38 | ) {
39 | callback.onShowProgress()
40 | if (repository.saveFavoriteTvShow(context, data)) {
41 | callback.onHideProgress()
42 | callback.onSuccesInsert()
43 | eventIsFavorite.postValue(true)
44 | } else {
45 | callback.onHideProgress()
46 | callback.onFailed("Failed")
47 | }
48 | }
49 |
50 | fun deleteFavoriteTvShow(
51 | tableId: Int,
52 | callback: com.frogobox.base.callback.DeleteViewCallback
53 | ) {
54 | callback.onShowProgress()
55 | if (repository.deleteFavoriteMovieProvider(context, tableId)) {
56 | callback.onHideProgress()
57 | callback.onSuccesDelete()
58 | eventIsFavorite.postValue(false)
59 | } else {
60 | callback.onHideProgress()
61 | callback.onFailed("Failed")
62 | }
63 | }
64 |
65 | fun getFavoriteTvShow(id: Int) {
66 | repository.getFavoriteTvShowCursor(context, object : DataSource.GetLocalCallBack {
67 | override fun onShowProgressDialog() {
68 | eventShowProgress.postValue(true)
69 | }
70 |
71 | override fun onHideProgressDialog() {
72 | eventShowProgress.postValue(false)
73 | }
74 |
75 | override fun onSuccess(data: Cursor) {
76 |
77 | val tempFavoriteList = mutableListOf()
78 | tempFavoriteList.clear()
79 | tempFavoriteList.addAll(setupCursor(data))
80 |
81 | for (i in tempFavoriteList.indices) {
82 | if (tempFavoriteList[i].id!! == id) {
83 | eventIsEmpty.postValue(false)
84 | eventIsFavorite.postValue(true)
85 | favoriteTvShow.postValue(tempFavoriteList[i])
86 | break
87 | } else {
88 | eventIsEmpty.postValue(true)
89 | eventIsFavorite.postValue(false)
90 | }
91 | }
92 | }
93 |
94 | override fun onFinish() {}
95 |
96 | override fun onEmpty() {
97 | eventIsEmpty.postValue(true)
98 | eventIsFavorite.postValue(false)
99 | }
100 |
101 | override fun onFailed(statusCode: Int, errorMessage: String?) {}
102 | })
103 | }
104 |
105 | }
--------------------------------------------------------------------------------
/favorite/src/main/java/com/frogobox/favorite/mvvm/tv/TvShowFragment.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.favorite.mvvm.tv
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.fragment.app.Fragment
7 | import androidx.lifecycle.Observer
8 | import androidx.recyclerview.widget.LinearLayoutManager
9 | import com.frogobox.base.source.model.FavoriteTvShow
10 | import com.frogobox.base.adapter.FavoriteTvShowAdapter
11 | import com.frogobox.base.BaseFragment
12 | import com.frogobox.base.BaseListener
13 | import com.frogobox.favorite.mvvm.main.MainActivity
14 | import com.frogobox.favorite.R
15 | import com.frogobox.favorite.databinding.FragmentTvMovieListBinding
16 |
17 | /**
18 | * A simple [Fragment] subclass.
19 | */
20 | class TvShowFragment : BaseFragment(),
21 | BaseListener {
22 |
23 | private lateinit var mViewModel: TvShowViewModel
24 |
25 | override fun setupViewBinding(
26 | inflater: LayoutInflater,
27 | container: ViewGroup
28 | ): FragmentTvMovieListBinding {
29 | return FragmentTvMovieListBinding.inflate(inflater, container, false)
30 | }
31 |
32 | override fun setupViewModel() {
33 | mViewModel = (activity as MainActivity).obtainTvShowViewModel().apply {
34 |
35 | favTvShowListLive.observe(viewLifecycleOwner) {
36 | setupRecyclerView(it)
37 | }
38 |
39 | eventShowProgress.observe(viewLifecycleOwner) {
40 | setupEventProgressView(binding?.progressBar!!, it)
41 | }
42 |
43 | eventIsEmpty.observe(viewLifecycleOwner) {
44 | // setupEventEmptyView(empty_view, it)
45 | }
46 |
47 | }
48 | }
49 |
50 |
51 | override fun setupUI(savedInstanceState: Bundle?) {
52 | getTvShow()
53 | }
54 |
55 | private fun getTvShow() {
56 | mViewModel.getFavoriteTvShow()
57 | }
58 |
59 | override fun onResume() {
60 | super.onResume()
61 | getTvShow()
62 | }
63 |
64 | private fun setupRecyclerView(data: List) {
65 | val adapter = FavoriteTvShowAdapter()
66 | context?.let { adapter.setRecyclerViewLayout(it, R.layout.item_list_tv_movie) }
67 | adapter.setRecyclerViewListener(this)
68 | adapter.setRecyclerViewData(data)
69 | binding?.apply {
70 | recyclerView.adapter = adapter
71 | recyclerView.layoutManager =
72 | LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
73 | }
74 | }
75 |
76 | override fun onItemClicked(data: FavoriteTvShow) {
77 | context?.let {
78 | baseStartActivity(
79 | it,
80 | DetailTvShowActivity.EXTRA_FAV_TV,
81 | data
82 | )
83 | }
84 | }
85 |
86 | override fun onItemLongClicked(data: FavoriteTvShow) {}
87 |
88 | }
--------------------------------------------------------------------------------
/favorite/src/main/java/com/frogobox/favorite/mvvm/tv/TvShowViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.favorite.mvvm.tv
2 |
3 | import android.app.Application
4 | import android.database.Cursor
5 | import com.frogobox.base.BaseViewModel
6 | import com.frogobox.base.source.model.FavoriteTvShow
7 | import com.frogobox.base.source.DataSource
8 | import com.frogobox.base.source.Repository
9 | import com.frogobox.base.util.Constant.RoomDatabase.TvShow.setupCursor
10 | import com.frogobox.base.util.SingleLiveEvent
11 |
12 | /**
13 | * Created by Faisal Amir
14 | * FrogoBox Inc License
15 | * =========================================
16 | * movie
17 | * Copyright (C) 16/11/2019.
18 | * All rights reserved
19 | * -----------------------------------------
20 | * Name : Muhammad Faisal Amir
21 | * E-mail : faisalamircs@gmail.com
22 | * Github : github.com/amirisback
23 | * LinkedIn : linkedin.com/in/faisalamircs
24 | * -----------------------------------------
25 | * FrogoBox Software Industries
26 | * com.frogobox.favorite
27 | *
28 | */
29 | class TvShowViewModel(private val context: Application, private val repository: Repository) :
30 | BaseViewModel(context) {
31 |
32 | var favTvShowListLive = SingleLiveEvent>()
33 |
34 | fun getFavoriteTvShow() {
35 | repository.getFavoriteTvShowCursor(context, object : DataSource.GetLocalCallBack {
36 | override fun onShowProgressDialog() {
37 | eventShowProgress.postValue(true)
38 | }
39 |
40 | override fun onHideProgressDialog() {
41 | eventShowProgress.postValue(false)
42 | }
43 |
44 | override fun onSuccess(data: Cursor) {
45 | eventIsEmpty.postValue(false)
46 | favTvShowListLive.postValue(setupCursor(data))
47 | }
48 |
49 | override fun onFinish() {
50 |
51 | }
52 |
53 | override fun onEmpty() {
54 | eventIsEmpty.postValue(true)
55 | }
56 |
57 | override fun onFailed(statusCode: Int, errorMessage: String?) {
58 |
59 | }
60 | })
61 | }
62 |
63 | }
--------------------------------------------------------------------------------
/favorite/src/main/java/com/frogobox/favorite/util/BaseFavoriteActivity.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.favorite.util
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.ViewModelProvider
5 | import androidx.viewbinding.ViewBinding
6 | import com.frogobox.base.BaseActivity
7 |
8 | /**
9 | * Created by Faisal Amir
10 | * FrogoBox Inc License
11 | * =========================================
12 | * movie
13 | * Copyright (C) 16/11/2019.
14 | * All rights reserved
15 | * -----------------------------------------
16 | * Name : Muhammad Faisal Amir
17 | * E-mail : faisalamircs@gmail.com
18 | * Github : github.com/amirisback
19 | * LinkedIn : linkedin.com/in/faisalamircs
20 | * -----------------------------------------
21 | * FrogoBox Software Industries
22 | * com.frogobox.favorite
23 | *
24 | */
25 | abstract class BaseFavoriteActivity : BaseActivity() {
26 |
27 | fun obtainViewModel(viewModelClass: Class) =
28 | ViewModelProvider(
29 | this,
30 | ViewModelFactory.getInstance(application)
31 | ).get(viewModelClass)
32 |
33 | }
--------------------------------------------------------------------------------
/favorite/src/main/java/com/frogobox/favorite/util/ViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package com.frogobox.favorite.util
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Application
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.ViewModelProvider
7 | import com.frogobox.base.source.Repository
8 | import com.frogobox.base.util.Injection
9 | import com.frogobox.favorite.mvvm.movie.DetailMovieViewModel
10 | import com.frogobox.favorite.mvvm.tv.DetailTvShowViewModel
11 | import com.frogobox.favorite.mvvm.movie.MovieViewModel
12 | import com.frogobox.favorite.mvvm.tv.TvShowViewModel
13 |
14 | /**
15 | * Created by Faisal Amir
16 | * FrogoBox Inc License
17 | * =========================================
18 | * movie
19 | * Copyright (C) 16/11/2019.
20 | * All rights reserved
21 | * -----------------------------------------
22 | * Name : Muhammad Faisal Amir
23 | * E-mail : faisalamircs@gmail.com
24 | * Github : github.com/amirisback
25 | * LinkedIn : linkedin.com/in/faisalamircs
26 | * -----------------------------------------
27 | * FrogoBox Software Industries
28 | * com.frogobox.favorite
29 | *
30 | */
31 | class ViewModelFactory private constructor(
32 | private val mApplication: Application,
33 | private val repository: Repository
34 | ) : ViewModelProvider.NewInstanceFactory() {
35 |
36 | @Suppress("UNCHECKED_CAST")
37 | override fun create(modelClass: Class): T =
38 | with(modelClass) {
39 | when {
40 |
41 | isAssignableFrom(MovieViewModel::class.java) ->
42 | MovieViewModel(mApplication, repository)
43 |
44 | isAssignableFrom(TvShowViewModel::class.java) ->
45 | TvShowViewModel(mApplication, repository)
46 |
47 | isAssignableFrom(DetailMovieViewModel::class.java) ->
48 | DetailMovieViewModel(mApplication, repository)
49 |
50 | isAssignableFrom(DetailTvShowViewModel::class.java) ->
51 | DetailTvShowViewModel(mApplication, repository)
52 |
53 |
54 | else ->
55 | throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
56 | }
57 | } as T
58 |
59 | companion object {
60 |
61 | @SuppressLint("StaticFieldLeak")
62 | @Volatile private var INSTANCE: ViewModelFactory? = null
63 |
64 | fun getInstance(mApplication: Application) =
65 | INSTANCE
66 | ?: synchronized(ViewModelFactory::class.java) {
67 | INSTANCE
68 | ?: ViewModelFactory(
69 | mApplication,
70 | Injection.provideRepository(mApplication.applicationContext)
71 | )
72 | .also { INSTANCE = it }
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/favorite/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/favorite/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
22 |
23 |
32 |
33 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/favorite/src/main/res/layout/fragment_tv_movie_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
30 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/favorite/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/favorite/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/favorite/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/favorite/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Hello blank fragment
3 |
4 |
--------------------------------------------------------------------------------
/favorite/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frogobox/kick-start-android-modular/8cb6e3c49650be2dfe586570d44dd76c207a4598/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jun 24 09:00:12 ICT 2020
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-7.2-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
7 | maven { url = uri("https://jitpack.io") }
8 | }
9 | }
10 |
11 | dependencyResolutionManagement {
12 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
13 | repositories {
14 | google()
15 | mavenCentral()
16 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
17 | maven { url = uri("https://jitpack.io") }
18 | }
19 | }
20 |
21 | rootProject.name="movie"
22 | include(":app", ":base", ":favorite")
23 |
--------------------------------------------------------------------------------