mirror of
https://github.com/melihaksoy/Android-Kotlin-Modulerized-CleanArchitecture.git
synced 2026-01-11 20:00:32 +01:00
Single activity approach (#30)
* CircleCI config fixes * Implicit deeplinking via navController navigate * Removed jacoco.exec files. Closes # 32
This commit is contained in:
@@ -26,19 +26,66 @@ jobs:
|
||||
command: fastlane detekt
|
||||
- store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
|
||||
path: reports/detekt
|
||||
- store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
|
||||
path: reports
|
||||
|
||||
# Tests
|
||||
## App
|
||||
- run:
|
||||
name: Tests
|
||||
name: Test App
|
||||
command: |
|
||||
fastlane test_all
|
||||
./gradlew jacocoTestReport
|
||||
fastlane test_app
|
||||
./gradlew app:jacocoTestReport
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
- store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
|
||||
path: build/reports/tests
|
||||
path: app/build/reports/tests
|
||||
- store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
|
||||
path: reports
|
||||
path: app/build/test-results
|
||||
|
||||
## Core
|
||||
- run:
|
||||
name: Test Core
|
||||
command: |
|
||||
fastlane test_core
|
||||
./gradlew core:jacocoTestReport
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
- store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
|
||||
path: core/build/reports/tests
|
||||
- store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
|
||||
path: core/build/test-results
|
||||
|
||||
## Launches
|
||||
- run:
|
||||
name: Test Launches
|
||||
command: |
|
||||
fastlane test_launches
|
||||
./gradlew features:launches:jacocoTestReport
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
- store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
|
||||
path: features/launches/build/reports/tests
|
||||
- store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
|
||||
path: features/launches/build/test-results
|
||||
|
||||
## Detail
|
||||
- run:
|
||||
name: Test Detail
|
||||
command: |
|
||||
fastlane test_detail
|
||||
./gradlew features:detail:jacocoTestReport
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
- store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
|
||||
path: features/detail/build/reports/tests
|
||||
- store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
|
||||
path: features/detail/build/test-results
|
||||
|
||||
## Repository
|
||||
- run:
|
||||
name: Test Repository
|
||||
command: |
|
||||
fastlane test_repository
|
||||
./gradlew repository:jacocoTestReport
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
- store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
|
||||
path: repository/build/reports/tests
|
||||
- store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
|
||||
path: repository/build/test-results
|
||||
|
||||
# See https://circleci.com/docs/2.0/deployment-integrations/ for deploy examples
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -4,6 +4,8 @@
|
||||
/.idea
|
||||
.DS_Store
|
||||
/build
|
||||
/fastlane/README.md
|
||||
/fastlane/report.xml
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
/projectFilesBackup
|
||||
@@ -11,3 +13,6 @@
|
||||
|
||||
# Project reports
|
||||
/reports
|
||||
|
||||
#jacoco.exec
|
||||
jacoco.exec
|
||||
|
||||
159
Gemfile.lock
Normal file
159
Gemfile.lock
Normal file
@@ -0,0 +1,159 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.0)
|
||||
addressable (2.6.0)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
atomos (0.1.3)
|
||||
babosa (1.0.2)
|
||||
claide (1.0.3)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander-fastlane (4.4.6)
|
||||
highline (~> 1.7.2)
|
||||
declarative (0.0.10)
|
||||
declarative-option (0.1.0)
|
||||
digest-crc (0.4.1)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.7.5)
|
||||
emoji_regex (1.0.1)
|
||||
excon (0.66.0)
|
||||
faraday (0.15.4)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday-cookie_jar (0.0.6)
|
||||
faraday (>= 0.7.4)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday_middleware (0.13.1)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fastimage (2.1.5)
|
||||
fastlane (2.129.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
babosa (>= 1.0.2, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored
|
||||
commander-fastlane (>= 4.4.6, < 5.0.0)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 2.0)
|
||||
excon (>= 0.45.0, < 1.0.0)
|
||||
faraday (~> 0.9)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 0.9)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-api-client (>= 0.21.2, < 0.24.0)
|
||||
google-cloud-storage (>= 1.15.0, < 2.0.0)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
json (< 3.0.0)
|
||||
jwt (~> 2.1.0)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multi_xml (~> 0.5)
|
||||
multipart-post (~> 2.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
public_suffix (~> 2.0.0)
|
||||
rubyzip (>= 1.2.2, < 2.0.0)
|
||||
security (= 0.1.3)
|
||||
simctl (~> 1.6.3)
|
||||
slack-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.8.1, < 2.0.0)
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
gh_inspector (1.1.3)
|
||||
google-api-client (0.23.9)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (>= 0.5, < 0.7.0)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
mime-types (~> 3.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
signet (~> 0.9)
|
||||
google-cloud-core (1.3.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-env (1.2.0)
|
||||
faraday (~> 0.11)
|
||||
google-cloud-storage (1.16.0)
|
||||
digest-crc (~> 0.4)
|
||||
google-api-client (~> 0.23)
|
||||
google-cloud-core (~> 1.2)
|
||||
googleauth (>= 0.6.2, < 0.10.0)
|
||||
googleauth (0.6.7)
|
||||
faraday (~> 0.12)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.7)
|
||||
highline (1.7.10)
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
json (2.2.0)
|
||||
jwt (2.1.0)
|
||||
memoist (0.16.0)
|
||||
mime-types (3.2.2)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2019.0331)
|
||||
mini_magick (4.9.5)
|
||||
multi_json (1.13.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
nanaimo (0.2.6)
|
||||
naturally (2.2.0)
|
||||
os (1.0.1)
|
||||
plist (3.5.0)
|
||||
public_suffix (2.0.5)
|
||||
representable (3.0.4)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rouge (2.0.7)
|
||||
rubyzip (1.2.3)
|
||||
security (0.1.3)
|
||||
signet (0.11.0)
|
||||
addressable (~> 2.3)
|
||||
faraday (~> 0.9)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.5)
|
||||
CFPropertyList
|
||||
naturally
|
||||
slack-notifier (2.3.2)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
tty-cursor (0.7.0)
|
||||
tty-screen (0.7.0)
|
||||
tty-spinner (0.9.1)
|
||||
tty-cursor (~> 0.7)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.6)
|
||||
unicode-display_width (1.6.0)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.12.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.2.6)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.0)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
fastlane
|
||||
|
||||
BUNDLED WITH
|
||||
2.0.1
|
||||
@@ -37,4 +37,7 @@ dependencies {
|
||||
compileOnly libraries.retrofit
|
||||
compileOnly libraries.room
|
||||
compileOnly libraries.paging
|
||||
|
||||
// Need for proper renders in xml previews
|
||||
compileOnly libraries.constraintLayout
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.melih.rocketscience">
|
||||
|
||||
@@ -13,5 +14,15 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning" />
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<nav-graph android:value="@navigation/nav_main" />
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
31
app/src/main/kotlin/com/melih/rocketscience/MainActivity.kt
Normal file
31
app/src/main/kotlin/com/melih/rocketscience/MainActivity.kt
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.melih.rocketscience
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.ui.NavigationUI
|
||||
import com.melih.rocketscience.databinding.MainActivityBinding
|
||||
import dagger.android.support.DaggerAppCompatActivity
|
||||
|
||||
class MainActivity : DaggerAppCompatActivity() {
|
||||
|
||||
private lateinit var binding: MainActivityBinding
|
||||
private lateinit var navController: NavController
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
|
||||
|
||||
navController = findNavController(R.id.nav_host_fragment)
|
||||
NavigationUI.setupWithNavController(binding.toolbar, navController)
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
if (!NavigationUI.navigateUp(navController, null)) {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.melih.rocketscience.di
|
||||
|
||||
import com.melih.core.di.CoreComponent
|
||||
import com.melih.detail.di.DetailFeatureModule
|
||||
import com.melih.list.di.LaunchesFeatureModule
|
||||
import com.melih.rocketscience.App
|
||||
import dagger.Component
|
||||
import dagger.android.AndroidInjectionModule
|
||||
@@ -11,8 +9,7 @@ import dagger.android.AndroidInjector
|
||||
@AppScope
|
||||
@Component(
|
||||
modules = [AndroidInjectionModule::class,
|
||||
LaunchesFeatureModule::class,
|
||||
DetailFeatureModule::class],
|
||||
AppModule::class],
|
||||
|
||||
dependencies = [CoreComponent::class]
|
||||
)
|
||||
|
||||
19
app/src/main/kotlin/com/melih/rocketscience/di/AppModule.kt
Normal file
19
app/src/main/kotlin/com/melih/rocketscience/di/AppModule.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.melih.rocketscience.di
|
||||
|
||||
import com.melih.detail.di.DetailContributor
|
||||
import com.melih.list.di.LaunchesContributor
|
||||
import com.melih.rocketscience.MainActivity
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
|
||||
@Module
|
||||
abstract class AppModule {
|
||||
|
||||
|
||||
@ContributesAndroidInjector(
|
||||
modules = [
|
||||
LaunchesContributor::class,
|
||||
DetailContributor::class]
|
||||
)
|
||||
abstract fun mainActivity(): MainActivity
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<layout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<data class="LaunchesActivityBinding" />
|
||||
<data class="MainActivityBinding" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -14,9 +16,12 @@
|
||||
android:layout_height="?android:actionBarSize"
|
||||
android:background="@color/colorPrimary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/container"
|
||||
<fragment
|
||||
android:id="@+id/nav_host_fragment"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/nav_main" />
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
10
app/src/main/res/navigation/nav_main.xml
Normal file
10
app/src/main/res/navigation/nav_main.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/nav_main"
|
||||
app:startDestination="@id/nav_launches">
|
||||
|
||||
<include app:graph="@navigation/nav_launches" />
|
||||
<include app:graph="@navigation/nav_detail" />
|
||||
</navigation>
|
||||
@@ -9,7 +9,7 @@ buildscript {
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.0-rc03'
|
||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:0.9.18"
|
||||
classpath "de.mannodermaus.gradle.plugins:android-junit5:1.5.0.0"
|
||||
|
||||
BIN
core/jacoco.exec
BIN
core/jacoco.exec
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.melih.core">
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.melih.core">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
</manifest>
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package com.melih.core.actions
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
const val EXTRA_LAUNCH_ID = "extras:detail:launchid"
|
||||
import android.net.Uri
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import com.melih.core.R
|
||||
|
||||
/**
|
||||
* Navigation actions for navigation between feature activities
|
||||
*/
|
||||
object Actions {
|
||||
|
||||
fun openDetailFor(id: Long) =
|
||||
Intent("action.dashboard.open")
|
||||
.putExtra(EXTRA_LAUNCH_ID, id)
|
||||
|
||||
}
|
||||
fun Fragment.openDetail(id: Long) =
|
||||
NavHostFragment.findNavController(this).navigate(Uri.parse(getString(R.string.detail_uri, id)))
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.melih.core.base.lifecycle
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.ui.NavigationUI
|
||||
import dagger.android.support.DaggerAppCompatActivity
|
||||
|
||||
const val NAV_HOST_FRAGMENT_TAG = "nav_host_fragment_tag"
|
||||
|
||||
/**
|
||||
* Base class of all Activity classes
|
||||
*/
|
||||
abstract class BaseActivity<T : ViewDataBinding> : DaggerAppCompatActivity() {
|
||||
|
||||
protected lateinit var binding: T
|
||||
protected lateinit var navHostFragment: NavHostFragment
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = DataBindingUtil.setContentView(this, getLayoutId())
|
||||
binding.lifecycleOwner = this
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
navHostFragment = createNavHostFragment()
|
||||
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.add(addNavHostTo(), navHostFragment, NAV_HOST_FRAGMENT_TAG)
|
||||
.commitNow()
|
||||
} else {
|
||||
navHostFragment = supportFragmentManager
|
||||
.findFragmentByTag(NAV_HOST_FRAGMENT_TAG) as NavHostFragment
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
if (!NavigationUI.navigateUp(navHostFragment.navController, null)) {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
abstract fun getLayoutId(): Int
|
||||
|
||||
abstract fun createNavHostFragment(): NavHostFragment
|
||||
|
||||
@IdRes
|
||||
abstract fun addNavHostTo(): Int
|
||||
}
|
||||
@@ -8,9 +8,8 @@ import androidx.annotation.LayoutRes
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.melih.core.R
|
||||
import com.melih.repository.interactors.base.Reason
|
||||
|
||||
/**
|
||||
@@ -23,7 +22,6 @@ abstract class BaseFragment<T : ViewDataBinding> : Fragment() {
|
||||
|
||||
// region Properties
|
||||
|
||||
protected lateinit var navController: NavController
|
||||
protected lateinit var binding: T
|
||||
// endregion
|
||||
|
||||
@@ -34,7 +32,6 @@ abstract class BaseFragment<T : ViewDataBinding> : Fragment() {
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
navController = NavHostFragment.findNavController(this)
|
||||
binding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false)
|
||||
binding.lifecycleOwner = this
|
||||
return binding.root
|
||||
@@ -45,7 +42,7 @@ abstract class BaseFragment<T : ViewDataBinding> : Fragment() {
|
||||
binding.root,
|
||||
resources.getString(reason.messageRes),
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
).setAction(com.melih.core.R.string.retry) {
|
||||
).setAction(R.string.retry) {
|
||||
block()
|
||||
}.show()
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!DOCTYPE
|
||||
resources[<!ENTITY deeplinkNamespace "rocket-science://"><!ENTITY deeplinkDetailPath "&deeplinkNamespace;detail"><!ENTITY paramLaunchId "launch-id">]>
|
||||
|
||||
<resources>
|
||||
<string name="dummy_long_text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
||||
incididunt ut labore et dolore
|
||||
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat. Duis aute irure dolor in
|
||||
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
|
||||
non proident, sunt in culpa qui officia
|
||||
deserunt mollit anim id est laborum
|
||||
</string>
|
||||
<string name="retry">Retry</string>
|
||||
|
||||
<string name="retry">Retry</string>
|
||||
|
||||
<!--Actions-->
|
||||
<string name="action_detail">action.detail.open</string>
|
||||
<string name="detail_param_launch_id">¶mLaunchId;</string>
|
||||
<string name="detail_deeplink">&deeplinkDetailPath;/{¶mLaunchId;}</string>
|
||||
<string name="detail_uri">&deeplinkDetailPath;/%1d</string>
|
||||
</resources>
|
||||
|
||||
@@ -30,9 +30,29 @@ platform :android do
|
||||
run_detekt()
|
||||
end
|
||||
|
||||
desc "Runs all tests in all modules"
|
||||
lane :test_all do
|
||||
run_all_tests()
|
||||
desc "Runs tests in app module"
|
||||
lane :test_app do
|
||||
run_app_tests()
|
||||
end
|
||||
|
||||
desc "Runs tests in core module"
|
||||
lane :test_core do
|
||||
run_core_tests()
|
||||
end
|
||||
|
||||
desc "Runs tests in launches module"
|
||||
lane :test_launches do
|
||||
run_launches_tests()
|
||||
end
|
||||
|
||||
desc "Runs tests in detail module"
|
||||
lane :test_detail do
|
||||
run_detail_tests()
|
||||
end
|
||||
|
||||
desc "Runs tests in repository module"
|
||||
lane :test_repository do
|
||||
run_repository_tests()
|
||||
end
|
||||
|
||||
# ================ Gradle tasks ================
|
||||
@@ -45,7 +65,23 @@ platform :android do
|
||||
gradle(task: "removeReports")
|
||||
end
|
||||
|
||||
def run_all_tests
|
||||
gradle(task: "clean test --continue")
|
||||
def run_app_tests
|
||||
gradle(task: "app:test --continue")
|
||||
end
|
||||
|
||||
def run_core_tests
|
||||
gradle(task: "core:test --continue")
|
||||
end
|
||||
|
||||
def run_launches_tests
|
||||
gradle(task: "features:launches:test --continue")
|
||||
end
|
||||
|
||||
def run_detail_tests
|
||||
gradle(task: "features:detail:test --continue")
|
||||
end
|
||||
|
||||
def run_repository_tests
|
||||
gradle(task: "repository:test --continue")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: "androidx.navigation.safeargs"
|
||||
|
||||
apply from: "$rootProject.projectDir/scripts/feature_module.gradle"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,14 +1 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.melih.detail">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name="com.melih.detail.ui.DetailActivity"
|
||||
android:theme="@style/AppTheme">
|
||||
<intent-filter>
|
||||
<action android:name="action.dashboard.open" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
<manifest package="com.melih.detail" />
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.melih.detail.di
|
||||
|
||||
import com.melih.detail.ui.DetailActivity
|
||||
import com.melih.list.di.scopes.DetailScope
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
|
||||
/**
|
||||
* Contributes fragments & view models in this module
|
||||
*/
|
||||
@Module
|
||||
abstract class DetailFeatureModule {
|
||||
|
||||
// region Contributes
|
||||
|
||||
@ContributesAndroidInjector(
|
||||
modules = [
|
||||
DetailContributor::class
|
||||
]
|
||||
)
|
||||
@DetailScope
|
||||
abstract fun detailActivity(): DetailActivity
|
||||
// endregion
|
||||
}
|
||||
@@ -32,7 +32,7 @@ abstract class DetailFragmentModule {
|
||||
@Provides
|
||||
@JvmStatic
|
||||
fun provideGetLaunchDetailParams(fragment: DetailFragment): GetLaunchDetails.Params {
|
||||
val args: DetailFragmentArgs by fragment.navArgs()
|
||||
val args by fragment.navArgs<DetailFragmentArgs>()
|
||||
return GetLaunchDetails.Params(args.launchId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.melih.detail.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import com.melih.core.actions.EXTRA_LAUNCH_ID
|
||||
import com.melih.core.base.lifecycle.BaseActivity
|
||||
import com.melih.detail.R
|
||||
import com.melih.detail.databinding.DetailActivityBinding
|
||||
|
||||
const val INVALID_LAUNCH_ID = -1L
|
||||
|
||||
class DetailActivity : BaseActivity<DetailActivityBinding>() {
|
||||
|
||||
// region Functions
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setSupportActionBar(binding.toolbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
|
||||
override fun getLayoutId(): Int = R.layout.activity_detail
|
||||
|
||||
override fun createNavHostFragment() =
|
||||
NavHostFragment.create(
|
||||
R.navigation.nav_detail,
|
||||
DetailFragmentArgs.Builder()
|
||||
.setLaunchId(intent?.extras?.getLong(EXTRA_LAUNCH_ID) ?: INVALID_LAUNCH_ID)
|
||||
.build()
|
||||
.toBundle()
|
||||
)
|
||||
|
||||
override fun addNavHostTo(): Int = R.id.container
|
||||
// endregion
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<data class="DetailActivityBinding" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:actionBarSize"
|
||||
android:background="@color/colorPrimary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
@@ -1,18 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/nav_detail"
|
||||
app:startDestination="@id/detailFragment">
|
||||
<navigation
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/nav_detail"
|
||||
app:startDestination="@id/detailFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/detailFragment"
|
||||
android:name="com.melih.detail.ui.DetailFragment"
|
||||
android:label="DetailFragment"
|
||||
tools:layout="@layout/fragment_detail">
|
||||
<argument
|
||||
android:name="launchId"
|
||||
android:defaultValue="-1L"
|
||||
app:argType="long" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/detailFragment"
|
||||
android:name="com.melih.detail.ui.DetailFragment"
|
||||
android:label="DetailFragment"
|
||||
tools:layout="@layout/fragment_detail">
|
||||
<argument
|
||||
android:name="launch-id"
|
||||
android:defaultValue="0L"
|
||||
app:argType="long" />
|
||||
<deepLink
|
||||
android:id="@+id/detailDeepLink"
|
||||
app:uri="@string/detail_deeplink" />
|
||||
</fragment>
|
||||
</navigation>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="cd_rocket_image">Image of the rocket</string>
|
||||
<string name="cd_rocket_image">Image of the rocket</string>
|
||||
</resources>
|
||||
|
||||
Binary file not shown.
@@ -1,14 +1 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.melih.list">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name="com.melih.list.ui.LaunchesActivity"
|
||||
android:theme="@style/AppTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
<manifest package="com.melih.list" />
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.melih.list.di
|
||||
|
||||
import com.melih.list.di.scopes.LaunchesScope
|
||||
import com.melih.list.ui.LaunchesActivity
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
|
||||
/**
|
||||
* Contributes fragments & view models in this module
|
||||
*/
|
||||
@Module
|
||||
abstract class LaunchesFeatureModule {
|
||||
|
||||
// region Contributes
|
||||
|
||||
@ContributesAndroidInjector(
|
||||
modules = [
|
||||
LaunchesContributor::class
|
||||
]
|
||||
)
|
||||
@LaunchesScope
|
||||
abstract fun launchesActivity(): LaunchesActivity
|
||||
// endregion
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.melih.list.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import com.melih.core.base.lifecycle.BaseActivity
|
||||
import com.melih.list.R
|
||||
import com.melih.list.databinding.LaunchesActivityBinding
|
||||
|
||||
class LaunchesActivity : BaseActivity<LaunchesActivityBinding>() {
|
||||
|
||||
// region Functions
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setSupportActionBar(binding.toolbar)
|
||||
}
|
||||
|
||||
override fun getLayoutId(): Int = R.layout.activity_launches
|
||||
|
||||
override fun createNavHostFragment() =
|
||||
NavHostFragment.create(R.navigation.nav_launches)
|
||||
|
||||
override fun addNavHostTo(): Int = R.id.container
|
||||
// endregion
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package com.melih.list.ui
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import com.melih.core.actions.Actions
|
||||
import com.melih.core.actions.openDetail
|
||||
import com.melih.core.base.lifecycle.BaseDaggerFragment
|
||||
import com.melih.core.extensions.createFor
|
||||
import com.melih.core.extensions.observe
|
||||
@@ -36,17 +36,6 @@ class LaunchesFragment : BaseDaggerFragment<ListBinding>(), SwipeRefreshLayout.O
|
||||
observeDataChanges()
|
||||
}
|
||||
|
||||
//override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
// inflater.inflate(R.menu.menu_rocket_list, menu)
|
||||
//
|
||||
// with(menu.findItem(R.id.search)) {
|
||||
// onExpandOrCollapse(::onSearchExpand, ::onSearchCollapse)
|
||||
// setSearchQueryListener(actionView as SearchView)
|
||||
// }
|
||||
//
|
||||
// super.onCreateOptionsMenu(menu, inflater)
|
||||
//}
|
||||
|
||||
private fun observeDataChanges() {
|
||||
|
||||
// Observing state to show loading
|
||||
@@ -64,30 +53,12 @@ class LaunchesFragment : BaseDaggerFragment<ListBinding>(), SwipeRefreshLayout.O
|
||||
observe(viewModel.pagedList) {
|
||||
launchesAdapter.submitList(it)
|
||||
}
|
||||
|
||||
//observe(viewModel.filteredItems) {
|
||||
// launchesAdapter.submitList(it)
|
||||
//}
|
||||
}
|
||||
|
||||
private fun onItemSelected(item: LaunchEntity) {
|
||||
startActivity(Actions.openDetailFor(item.id))
|
||||
openDetail(item.id)
|
||||
}
|
||||
|
||||
//private fun onSearchExpand() {
|
||||
// binding.swipeRefreshLayout.isEnabled = false
|
||||
//}
|
||||
|
||||
//private fun onSearchCollapse() {
|
||||
// binding.swipeRefreshLayout.isEnabled = true
|
||||
//}
|
||||
|
||||
//private fun setSearchQueryListener(searchView: SearchView) {
|
||||
// searchView.setOnQueryChangedListener {
|
||||
// viewModel.filterItemListBy(it)
|
||||
// }
|
||||
//}
|
||||
|
||||
override fun onRefresh() {
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<navigation
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/nav_launches"
|
||||
|
||||
@@ -10,4 +10,8 @@ android {
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
testOptions.unitTests.all {
|
||||
jvmArgs "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
apply plugin: "androidx.navigation.safeargs"
|
||||
apply from: "$rootProject.projectDir/scripts/module.gradle"
|
||||
|
||||
android {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
apply from: "$rootProject.projectDir/scripts/default_android_config.gradle"
|
||||
apply from: "$rootProject.projectDir/scripts/sources.gradle"
|
||||
apply from: "$rootProject.projectDir/scripts/flavors.gradle"
|
||||
apply from: "$rootProject.projectDir/scripts/flavors.gradle"
|
||||
|
||||
Reference in New Issue
Block a user