diff --git a/.circleci/config.yml b/.circleci/config.yml
index b37c6096..4fdf46be 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -2,7 +2,7 @@ version: 2
jobs:
build:
docker:
- - image: circleci/android:api-28-alpha
+ - image: circleci/android:api-30
environment:
ANDROID_HOME: "/opt/android/sdk"
JAVA_OPTIONS: "-Xms512m -Xmx3200m"
diff --git a/app/build.gradle b/app/build.gradle
index 8be04ea1..01c332ea 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -6,9 +6,6 @@ apply from: 'config/jacoco.gradle'
apply from: 'config/sonarqube.gradle'
android {
viewBinding.enabled = true
- lintOptions {
- abortOnError false
- }
signingConfigs {
umbrella_beta {
keyAlias 'umbrella'
@@ -27,12 +24,20 @@ android {
exclude module: 'httpclient'
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-iid'
+ resolutionStrategy.eachDependency { DependencyResolveDetails details ->
+ if (details.requested.group == 'com.google.dagger') {
+ details.useVersion "HEAD-SNAPSHOT"
+ }
+ }
}
}
packagingOptions {
- exclude 'META-INF/LICENSE*'
- exclude 'META-INF/DEPENDENCIES'
- exclude 'META-INF/NOTICE*'
+ jniLibs {
+ excludes += ['META-INF/LICENSE*', 'META-INF/NOTICE*']
+ }
+ resources {
+ excludes += ['META-INF/LICENSE*', 'META-INF/DEPENDENCIES', 'META-INF/NOTICE*']
+ }
}
androidExtensions {
@@ -41,8 +46,8 @@ android {
defaultConfig {
applicationId "org.secfirst.umbrella"
minSdkVersion 16
- compileSdkVersion 28
- targetSdkVersion 28
+ compileSdkVersion 31
+ targetSdkVersion 31
versionCode 56
versionName "1.0.32"
multiDexEnabled true
@@ -68,6 +73,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ lint {
+ abortOnError false
+ }
}
dependencies {
@@ -92,7 +100,8 @@ dependencies {
//Framework for replacing fragments
implementation "com.bluelinelabs:conductor:$conductor_version"
- implementation "com.bluelinelabs:conductor-support:$conductor_version_support"
+// implementation "com.bluelinelabs:conductor-support:$conductor_version_support"
+ implementation "com.bluelinelabs:conductor-viewpager:$conductor_version_support"
//OkHttp
implementation "com.squareup.okhttp3:okhttp:$okhttp3"
diff --git a/app/config/jacoco.gradle b/app/config/jacoco.gradle
index e6673a30..7ae4abdb 100644
--- a/app/config/jacoco.gradle
+++ b/app/config/jacoco.gradle
@@ -12,29 +12,33 @@ jacoco {
task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") {
group = "Reporting"
description = "Generate Jacoco coverage reports for Debug build"
- classDirectories = fileTree(
- dir: "$buildDir/intermediates/classes/debug",
- excludes: ['**/R.class',
- '**/R$*.class',
- '**/*$ViewBinder*.*',
- '**/*$InjectAdapter*.*',
- '**/*Injector*.*',
- '**/BuildConfig.*',
- '**/Manifest*.*',
- '**/*Test*.*',
- '**/*Activity*.*',
- '**/CiMattersApplication*.*',
- 'android/**/*.*']
+ getClassDirectories().setFrom(
+ fileTree(
+ dir: "$buildDir/intermediates/classes/debug",
+ excludes: ['**/R.class',
+ '**/R$*.class',
+ '**/*$ViewBinder*.*',
+ '**/*$InjectAdapter*.*',
+ '**/*Injector*.*',
+ '**/BuildConfig.*',
+ '**/Manifest*.*',
+ '**/*Test*.*',
+ '**/*Activity*.*',
+ '**/CiMattersApplication*.*',
+ 'android/**/*.*']
+ )
)
reports {
xml.enabled = true
html.enabled = true
}
- additionalSourceDirs = files(coverageSourceDirs)
- sourceDirectories = files(coverageSourceDirs)
- executionData = fileTree(dir: project.buildDir, includes: [
- 'jacoco/testDebugUnitTest.exec', 'outputs/code-coverage/connected/*coverage.ec'
- ])
+ getAdditionalSourceDirs().setFrom(files(coverageSourceDirs))
+ getSourceDirectories().setFrom(files(coverageSourceDirs))
+ getExecutionData().setFrom(
+ fileTree(dir: project.buildDir, includes: [
+ 'jacoco/testDebugUnitTest.exec', 'outputs/code-coverage/connected/*coverage.ec'
+ ])
+ )
// Bit hacky but fixes https://code.google.com/p/android/issues/detail?id=69174.
// We iterate through the compiled .class tree and rename $$ to $.
doFirst {
diff --git a/app/src/androidTest/AndroidManifest.xml b/app/src/androidTest/AndroidManifest.xml
new file mode 100644
index 00000000..d914c8df
--- /dev/null
+++ b/app/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b7b44218..071fb873 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,7 +21,9 @@
+ android:screenOrientation="portrait"
+ tools:ignore="LockedOrientationActivity"
+ android:exported="true">
@@ -39,7 +41,8 @@
android:label="@string/app_calc"
android:roundIcon="@mipmap/calc"
android:screenOrientation="portrait"
- android:targetActivity=".feature.main.MainActivity">
+ android:targetActivity=".feature.main.MainActivity"
+ android:exported="true">
@@ -55,7 +58,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_umbrella"
android:screenOrientation="portrait"
- android:targetActivity=".feature.main.MainActivity">
+ android:targetActivity=".feature.main.MainActivity"
+ android:exported="true">
diff --git a/app/src/main/java/org/secfirst/umbrella/component/DialogManager.kt b/app/src/main/java/org/secfirst/umbrella/component/DialogManager.kt
index c924b105..429fb166 100644
--- a/app/src/main/java/org/secfirst/umbrella/component/DialogManager.kt
+++ b/app/src/main/java/org/secfirst/umbrella/component/DialogManager.kt
@@ -15,7 +15,7 @@ class DialogManager(private val controller: Controller) {
}
init {
- controller.addLifecycleListener(object : Controller.LifecycleListener {
+ controller.addLifecycleListener(object : Controller.LifecycleListener() {
override fun postCreateView(controller: Controller, view: View) {
for (combo in combos) {
combo.dialog = combo.factory.createDialog(controller.activity)
diff --git a/app/src/main/java/org/secfirst/umbrella/component/WebViewController.kt b/app/src/main/java/org/secfirst/umbrella/component/WebViewController.kt
index f41aebd2..c6134af3 100644
--- a/app/src/main/java/org/secfirst/umbrella/component/WebViewController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/component/WebViewController.kt
@@ -51,7 +51,7 @@ class WebViewController(bundle: Bundle) : BaseController(bundle) {
private fun setUpWebView() {
webView?.let {
- it.loadUrl(url)
+ url?.let { it1 -> it.loadUrl(it1) }
it.webViewClient = object : WebViewClient() {
override fun onReceivedError(view: WebView, errorCode: Int, description: String, failingUrl: String) {
webViewLoad?.visibility = INVISIBLE
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/adapter/HostChecklistAdapter.kt b/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/adapter/HostChecklistAdapter.kt
index 60d9776f..c5b78b23 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/adapter/HostChecklistAdapter.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/adapter/HostChecklistAdapter.kt
@@ -3,7 +3,7 @@ package org.secfirst.umbrella.feature.checklist.view.adapter
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.Router
import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.support.RouterPagerAdapter
+import com.bluelinelabs.conductor.viewpager.RouterPagerAdapter
import org.secfirst.umbrella.R
import org.secfirst.umbrella.feature.checklist.view.controller.DashboardController
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/ChecklistController.kt b/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/ChecklistController.kt
index 2c30c349..69f822d2 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/ChecklistController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/ChecklistController.kt
@@ -64,7 +64,7 @@ class ChecklistController(bundle: Bundle) : BaseController(bundle), ChecklistVie
.setView(checklistViewDialog)
.create()
presenter.onAttach(this)
- presenter.submitChecklist(checklistId)
+ checklistId?.let { presenter.submitChecklist(it) }
checklistView.addNewItemChecklist.setOnClickListener { onAddItemClicked() }
swipeToDeleteCallback()
checkIsNavigation()
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/ChecklistCustomController.kt b/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/ChecklistCustomController.kt
index cfe3a963..793c48cd 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/ChecklistCustomController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/ChecklistCustomController.kt
@@ -76,8 +76,13 @@ class ChecklistCustomController(bundle: Bundle) : BaseController(bundle), Checkl
private fun submitChecklist() {
if (adapter.getChecklistItems().isNotEmpty())
- presenter.submitInsertCustomChecklist(checklistName,
- checklistId, adapter.getChecklistItems())
+ checklistName?.let {
+ checklistId?.let { it1 ->
+ presenter.submitInsertCustomChecklist(
+ it,
+ it1, adapter.getChecklistItems())
+ }
+ }
}
private fun initDeleteChecklistItem(view: View) {
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/DashboardController.kt b/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/DashboardController.kt
index 3af3fe2a..99990b79 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/DashboardController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/checklist/view/controller/DashboardController.kt
@@ -277,15 +277,17 @@ class DashboardController(bundle: Bundle) : BaseController(bundle), ChecklistVie
private fun shareDocument(fileToShare: File) {
val pm = context.packageManager
val uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, fileToShare)
- val shareIntent = ShareCompat.IntentBuilder.from(activity)
+ val shareIntent = activity?.let {
+ ShareCompat.IntentBuilder(it)
.setType(context.contentResolver.getType(uri))
.setStream(uri)
.intent
+ }
- shareIntent.action = Intent.ACTION_SEND
- shareIntent.putExtra(Intent.EXTRA_SUBJECT, FilenameUtils.removeExtension(fileToShare.name))
- shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- if (shareIntent.resolveActivity(pm) != null)
+ shareIntent?.action = Intent.ACTION_SEND
+ shareIntent?.putExtra(Intent.EXTRA_SUBJECT, FilenameUtils.removeExtension(fileToShare.name))
+ shareIntent?.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ if (shareIntent?.resolveActivity(pm) != null)
startActivity(Intent.createChooser(shareIntent, context.getString(R.string.export_lesson)))
}
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/difficulty/view/DifficultyController.kt b/app/src/main/java/org/secfirst/umbrella/feature/difficulty/view/DifficultyController.kt
index cf1df003..65fe8866 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/difficulty/view/DifficultyController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/difficulty/view/DifficultyController.kt
@@ -42,13 +42,13 @@ class DifficultyController(bundle: Bundle) : BaseController(bundle), DifficultyV
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedViewState: Bundle?): View {
presenter.onAttach(this)
- presenter.submitDifficulty(subjectId)
+ subjectId?.let { presenter.submitDifficulty(it) }
return inflater.inflate(R.layout.difficulty_view, container, false)
}
private fun onDifficultClick(position: Int) {
val itemSelected = difficultyAdapter.getItem(position)
- presenter.saveDifficultySelect(itemSelected, subjectId)
+ subjectId?.let { presenter.saveDifficultySelect(itemSelected, it) }
presenter.submitDifficultySelect(difficultyAdapter.getItems(position))
}
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/main/MainActivity.kt b/app/src/main/java/org/secfirst/umbrella/feature/main/MainActivity.kt
index ab3322f6..fe8f4cb1 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/main/MainActivity.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/main/MainActivity.kt
@@ -15,7 +15,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import com.bluelinelabs.conductor.Router
import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.attachRouter
+import com.bluelinelabs.conductor.Conductor.attachRouter
import com.github.tbouron.shakedetector.library.ShakeDetector
import com.google.android.material.bottomnavigation.BottomNavigationView
import dagger.android.AndroidInjection
@@ -59,7 +59,7 @@ class MainActivity : AppCompatActivity(), AdvancedSearchPresenter {
super.onCreate(savedInstanceState)
setLanguage()
setContentView(R.layout.main_view)
- router = attachRouter(baseContainer, savedInstanceState)
+ router = attachRouter(this@MainActivity, baseContainer, savedInstanceState)
performDI()
isDeepLink()
initNavigation()
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/reader/view/ReaderAdapter.kt b/app/src/main/java/org/secfirst/umbrella/feature/reader/view/ReaderAdapter.kt
index 8950f5e3..2e65ad1c 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/reader/view/ReaderAdapter.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/reader/view/ReaderAdapter.kt
@@ -3,7 +3,7 @@ package org.secfirst.umbrella.feature.reader.view
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.Router
import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.support.RouterPagerAdapter
+import com.bluelinelabs.conductor.viewpager.RouterPagerAdapter
import org.secfirst.umbrella.R
import org.secfirst.umbrella.feature.reader.view.feed.FeedSettingsController
import org.secfirst.umbrella.feature.reader.view.rss.RssController
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/search/presenter/SearchPresenterImp.kt b/app/src/main/java/org/secfirst/umbrella/feature/search/presenter/SearchPresenterImp.kt
index 4cf00923..73a62ac1 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/search/presenter/SearchPresenterImp.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/search/presenter/SearchPresenterImp.kt
@@ -30,6 +30,7 @@ import org.secfirst.umbrella.feature.search.interactor.SearchBaseInteractor
import org.secfirst.umbrella.feature.search.view.SearchView
import org.secfirst.umbrella.misc.wrapTextWithElement
import javax.inject.Inject
+import kotlin.collections.ArrayList
class SearchPresenterImp @Inject constructor(
@@ -102,7 +103,7 @@ class SearchPresenterImp @Inject const
),
// We leave this one alone cause it renders the main search view
SearchCriteria(
- ItemCriteria.TEXT.type.toLowerCase(),
+ ItemCriteria.TEXT.type.lowercase(),
FieldTypes.FREE_TEXT,
null,
null)
@@ -111,9 +112,9 @@ class SearchPresenterImp @Inject const
override fun getDataProvider(): DataProvider = object : DataProvider {
override fun findByCriteria(text: String, vararg additional: Pair>): Flowable> {
- val trimmedText = text.toLowerCase().trim()
- val type = additional.find { it.first.toLowerCase().contains(ItemCriteria.TYPE.type.toLowerCase()) }?.second
- val category = additional.find { it.first.toLowerCase().contains(ItemCriteria.CATEGORY.type.toLowerCase()) }?.second
+ val trimmedText = text.lowercase().trim()
+ val type = additional.find { it.first.lowercase().contains(ItemCriteria.TYPE.type.lowercase()) }?.second
+ val category = additional.find { it.first.lowercase().contains(ItemCriteria.CATEGORY.type.lowercase()) }?.second
val categoryId = ArrayList()
if (category != null) {
val categoriesId = SQLite.select()
@@ -122,7 +123,7 @@ class SearchPresenterImp @Inject const
categoriesId.forEach { categoryId.add(it.id) }
}
- val difficulty = additional.find { it.first.toLowerCase().contains(ItemCriteria.DIFFICULTY.type.toLowerCase()) }?.second
+ val difficulty = additional.find { it.first.lowercase().contains(ItemCriteria.DIFFICULTY.type.lowercase()) }?.second
val mutableMap: MutableList = mutableListOf()
when (type == null) {
@@ -160,7 +161,7 @@ class SearchPresenterImp @Inject const
val doc = Jsoup.parse(htmlText)
for (e in doc.body().allElements) {
for (tn in e.textNodes()) {
- tn.wrapTextWithElement(text, "");
+ tn.wrapTextWithElement(text, "")
}
}
doc.toString()
@@ -180,7 +181,7 @@ class SearchPresenterImp @Inject const
false -> {
SQLite.select()
.from(Form::class.java)
- .where(Form_Table.path.like("%${text.toLowerCase().trim()}%"))
+ .where(Form_Table.path.like("%${text.lowercase().trim()}%"))
.queryList().map { it.toSearchResult() }
}
}
@@ -195,17 +196,20 @@ class SearchPresenterImp @Inject const
category.forEach { cat.or(Content_Table.checklist_id.like("%$it%")) }
op.and(cat)
}
+ else -> {}
}
when (difficulty?.isNotEmpty()) {
true -> {
difficulty.forEach { dif.or(Content_Table.checklist_id.like("%/$it/%")) }
op.and(dif)
}
+ else -> {}
}
when (text.isNotEmpty()) {
true -> {
- op.and(Content_Table.check.like("%${text.toLowerCase().trim()}%"))
+ op.and(Content_Table.check.like("%${text.lowercase().trim()}%"))
}
+ else -> {}
}
return SQLite.select()
@@ -225,17 +229,20 @@ class SearchPresenterImp @Inject const
category.forEach { cat.or(Markdown_Table.difficulty_id.like("%$it%")) }
op.and(cat)
}
+ else -> {}
}
when (difficulty?.isNotEmpty()) {
true -> {
difficulty.forEach { dif.or(Markdown_Table.difficulty_id.like("%/$it/%")) }
op.and(dif)
}
+ else -> {}
}
when (text.isNotEmpty()) {
true -> {
- op.and(Markdown_Table.text.like("%${text.toLowerCase().trim()}%"))
+ op.and(Markdown_Table.text.like("%${text.lowercase().trim()}%"))
}
+ else -> {}
}
return SQLite.select()
.from(Markdown::class.java)
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/search/view/SearchController.kt b/app/src/main/java/org/secfirst/umbrella/feature/search/view/SearchController.kt
index 717f5cfc..1b6235d1 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/search/view/SearchController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/search/view/SearchController.kt
@@ -17,60 +17,64 @@ import org.secfirst.umbrella.feature.search.presenter.SearchBasePresenter
import javax.inject.Inject
class SearchController(bundle: Bundle) : BaseController(bundle), SearchView {
-
- @Inject
- internal lateinit var presenter: SearchBasePresenter
- private val query by lazy { args.getString(EXTRA_SEARCH_QUERY) }
- private lateinit var mainIntentAction: String
-
- constructor(query: String = "") : this(Bundle().apply {
- putString(EXTRA_SEARCH_QUERY, query)
- })
-
- override fun onInject() {
- DaggerSearchComponent.builder()
- .application(UmbrellaApplication.instance)
- .build()
- .inject(this)
- }
-
- override fun onAttach(view: View) {
- super.onAttach(view)
- setUpToolbar()
- }
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedViewState: Bundle?): View {
- presenter.onAttach(this)
- mainActivity.registerSearchProvider(presenter as AdvancedSearchPresenter)
- mainActivity.intent.action?.let { mainIntentAction = it }
- presenter.submitSearchQuery(query)
- mainActivity.hideNavigation()
- mainActivity.intent.action = Intent.ACTION_SEARCH
- mainActivity.intent.putExtra(SearchManager.QUERY, query)
- return inflater.inflate(R.layout.searching_view, container, false)
- }
-
- override fun onDestroyView(view: View) {
- super.onDestroyView(view)
- mainActivity.intent.action = mainIntentAction
- mainActivity.showNavigation()
- mainActivity.releaseSearchProvider()
- }
-
- override fun handleBack(): Boolean {
- return super.handleBack()
- }
-
- private fun setUpToolbar() {
- searchToolbar?.let {
- it.setTitle(R.string.search_results)
- it.setNavigationIcon(R.drawable.ic_action_back)
- it.setNavigationOnClickListener { mainActivity.onBackPressed() }
- }
- }
-
- companion object {
- private const val EXTRA_SEARCH_QUERY = "search_query"
- }
-
- }
\ No newline at end of file
+
+ @Inject
+ internal lateinit var presenter: SearchBasePresenter
+ private val query by lazy { args.getString(EXTRA_SEARCH_QUERY) }
+ private lateinit var mainIntentAction: String
+
+ constructor(query: String = "") : this(Bundle().apply {
+ putString(EXTRA_SEARCH_QUERY, query)
+ })
+
+ override fun onInject() {
+ DaggerSearchComponent.builder()
+ .application(UmbrellaApplication.instance)
+ .build()
+ .inject(this)
+ }
+
+ override fun onAttach(view: View) {
+ super.onAttach(view)
+ setUpToolbar()
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup,
+ savedViewState: Bundle?
+ ): View {
+ presenter.onAttach(this)
+ mainActivity.registerSearchProvider(presenter as AdvancedSearchPresenter)
+ mainActivity.intent.action?.let { mainIntentAction = it }
+ query?.let { presenter.submitSearchQuery(it) }
+ mainActivity.hideNavigation()
+ mainActivity.intent.action = Intent.ACTION_SEARCH
+ mainActivity.intent.putExtra(SearchManager.QUERY, query)
+ return inflater.inflate(R.layout.searching_view, container, false)
+ }
+
+ override fun onDestroyView(view: View) {
+ super.onDestroyView(view)
+ mainActivity.intent.action = mainIntentAction
+ mainActivity.showNavigation()
+ mainActivity.releaseSearchProvider()
+ }
+
+ override fun handleBack(): Boolean {
+ return super.handleBack()
+ }
+
+ private fun setUpToolbar() {
+ searchToolbar?.let {
+ it.setTitle(R.string.search_results)
+ it.setNavigationIcon(R.drawable.ic_action_back)
+ it.setNavigationOnClickListener { mainActivity.onBackPressed() }
+ }
+ }
+
+ companion object {
+ private const val EXTRA_SEARCH_QUERY = "search_query"
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/adapter/FilterAdapter.kt b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/adapter/FilterAdapter.kt
index b93a86f5..61635a62 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/adapter/FilterAdapter.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/adapter/FilterAdapter.kt
@@ -14,7 +14,7 @@ import org.secfirst.umbrella.data.database.difficulty.Difficulty
class FilterAdapter(context: Context, private val difficulties: List) :
ArrayAdapter(context, android.R.layout.simple_dropdown_item_1line, difficulties) {
- override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
return createViewFromResource(position, convertView, parent)
}
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/adapter/HostSegmentAdapter.kt b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/adapter/HostSegmentAdapter.kt
index 008211ee..0dd359cf 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/adapter/HostSegmentAdapter.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/adapter/HostSegmentAdapter.kt
@@ -3,16 +3,18 @@ package org.secfirst.umbrella.feature.segment.view.adapter
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.Router
import com.bluelinelabs.conductor.RouterTransaction
-import com.bluelinelabs.conductor.support.RouterPagerAdapter
+import com.bluelinelabs.conductor.viewpager.RouterPagerAdapter
import org.secfirst.umbrella.feature.checklist.view.controller.ChecklistController
import org.secfirst.umbrella.feature.segment.view.controller.SegmentController
import org.secfirst.umbrella.feature.segment.view.controller.SegmentDetailController
import org.secfirst.umbrella.misc.AppExecutors.Companion.uiContext
import org.secfirst.umbrella.misc.launchSilent
-class HostSegmentAdapter(host: Controller,
- private val controllers: List,
- private val segmentPageLimit: Int) : RouterPagerAdapter(host) {
+class HostSegmentAdapter(
+ host: Controller,
+ private val controllers: List,
+ private val segmentPageLimit: Int
+) : RouterPagerAdapter(host) {
override fun configureRouter(router: Router, position: Int) {
@@ -20,7 +22,13 @@ class HostSegmentAdapter(host: Controller,
when (position) {
0 -> {
val segmentController = controllers[position] as SegmentController
- launchSilent(uiContext) { router.setRoot(RouterTransaction.with(segmentController)) }
+ launchSilent(uiContext) {
+ router.setRoot(
+ RouterTransaction.with(
+ segmentController
+ )
+ )
+ }
}
in 1..segmentPageLimit -> {
val detailController = controllers[position] as SegmentDetailController
@@ -28,7 +36,13 @@ class HostSegmentAdapter(host: Controller,
}
else -> {
val checklistController = controllers[position] as ChecklistController
- launchSilent(uiContext) { router.setRoot(RouterTransaction.with(checklistController)) }
+ launchSilent(uiContext) {
+ router.setRoot(
+ RouterTransaction.with(
+ checklistController
+ )
+ )
+ }
}
}
}
@@ -42,7 +56,7 @@ class HostSegmentAdapter(host: Controller,
}
in 1..segmentPageLimit -> {
val currentController = controllers[position] as SegmentDetailController
- currentController.getTitle()
+ currentController.getTitle() ?: ""
}
else -> {
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/HostSegmentController.kt b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/HostSegmentController.kt
index 89c635f9..336ebdbc 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/HostSegmentController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/HostSegmentController.kt
@@ -66,17 +66,19 @@ class HostSegmentController(bundle: Bundle) : BaseController(bundle), SegmentVie
private fun initView(view: View) {
setUpToolbar(view)
- when {
- uriString != null -> presenter.submitMarkdownsByURI(uriString)
+ objectIds?.let {
+ when {
+ uriString != null -> presenter.submitMarkdownsByURI(uriString!!)
- enableFilter -> {
- view.hostSegmentSpinner.visibility = VISIBLE
- presenter.submitDifficulties(objectIds)
- }
+ enableFilter -> {
+ view.hostSegmentSpinner.visibility = VISIBLE
+ presenter.submitDifficulties(it)
+ }
- else -> {
- presenter.submitMarkdowns(objectIds)
- view.hostSegmentSpinner.visibility = INVISIBLE
+ else -> {
+ presenter.submitMarkdowns(it)
+ view.hostSegmentSpinner.visibility = INVISIBLE
+ }
}
}
}
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/SegmentController.kt b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/SegmentController.kt
index d11723fb..258142e0 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/SegmentController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/SegmentController.kt
@@ -68,7 +68,11 @@ class SegmentController(bundle: Bundle) : BaseController(bundle), SegmentView {
private lateinit var viewSegment: View
private lateinit var tabControl: HostSegmentTabControl
- constructor(markdownIds: ArrayList, checklistId: String, isFromDashboard: Boolean = false) : this(Bundle().apply {
+ constructor(
+ markdownIds: ArrayList,
+ checklistId: String,
+ isFromDashboard: Boolean = false
+ ) : this(Bundle().apply {
putStringArrayList(EXTRA_SEGMENT, markdownIds)
putString(EXTRA_CHECKLIST, checklistId)
putBoolean(EXTRA_DASHBOARD, isFromDashboard)
@@ -76,23 +80,31 @@ class SegmentController(bundle: Bundle) : BaseController(bundle), SegmentView {
override fun onInject() {
DaggerSegmentComponent.builder()
- .application(UmbrellaApplication.instance)
- .build()
- .inject(this)
+ .application(UmbrellaApplication.instance)
+ .build()
+ .inject(this)
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedViewState: Bundle?): View {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup,
+ savedViewState: Bundle?
+ ): View {
setHasOptionsMenu(true)
tabControl = parentController as HostSegmentTabControl
viewSegment = inflater.inflate(R.layout.segment_view, container, false)
shareView = inflater.inflate(R.layout.share_dialog, container, false)
- if (markdownIds.isNotEmpty()) {
+ if (markdownIds?.isNotEmpty() == true) {
shareDialog = AlertDialog
- .Builder(activity)
- .setView(shareView)
- .create()
+ .Builder(activity)
+ .setView(shareView)
+ .create()
presenter.onAttach(this)
- presenter.submitMarkdownsAndChecklist(markdownIds, checklistId)
+ checklistId?.let {
+ markdownIds?.let { it1 ->
+ presenter.submitMarkdownsAndChecklist(it1, it)
+ }
+ }
if (isFromDashboard) {
onSegmentClicked(markdownIds!!.size)
}
@@ -139,10 +151,12 @@ class SegmentController(bundle: Bundle) : BaseController(bundle), SegmentView {
launchSilent(uiContext) {
markdowns.forEach { markdown ->
if (markdown.isRemove) {
- val segmentItem = SegmentItem(segmentClick, segmentShareClick, segmentFavoriteClick, null)
+ val segmentItem =
+ SegmentItem(segmentClick, segmentShareClick, segmentFavoriteClick, null)
section.add(segmentItem)
} else {
- val segmentItem = SegmentItem(segmentClick, segmentShareClick, segmentFavoriteClick, markdown)
+ val segmentItem =
+ SegmentItem(segmentClick, segmentShareClick, segmentFavoriteClick, markdown)
section.add(segmentItem)
}
}
@@ -156,13 +170,25 @@ class SegmentController(bundle: Bundle) : BaseController(bundle), SegmentView {
private fun createChecklistCard() {
checklist?.let {
- segmentAdapter.add(Section(SegmentFoot(footClick,
- checklistShareClick, checklistFavoriteClick, it)))
+ segmentAdapter.add(
+ Section(
+ SegmentFoot(
+ footClick,
+ checklistShareClick, checklistFavoriteClick, it
+ )
+ )
+ )
}
}
override fun showSegmentDetail(markdown: Markdown) {
- parentController?.router?.pushController(RouterTransaction.with(SegmentDetailController(markdown)))
+ parentController?.router?.pushController(
+ RouterTransaction.with(
+ SegmentDetailController(
+ markdown
+ )
+ )
+ )
}
@@ -193,16 +219,23 @@ class SegmentController(bundle: Bundle) : BaseController(bundle), SegmentView {
private fun shareDocument(fileToShare: File) {
val pm = context.packageManager
val uri = FileProvider.getUriForFile(context, APPLICATION_ID, fileToShare)
- val shareIntent = ShareCompat.IntentBuilder.from(activity)
+ val shareIntent = activity?.let {
+ ShareCompat.IntentBuilder(it)
.setType(context.contentResolver.getType(uri))
.setStream(uri)
.intent
+ }
- shareIntent.action = Intent.ACTION_SEND
- shareIntent.putExtra(Intent.EXTRA_SUBJECT, removeExtension(fileToShare.name))
- shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- if (shareIntent.resolveActivity(pm) != null)
- startActivity(Intent.createChooser(shareIntent, context.getString(R.string.export_lesson)))
+ shareIntent?.action = Intent.ACTION_SEND
+ shareIntent?.putExtra(Intent.EXTRA_SUBJECT, removeExtension(fileToShare.name))
+ shareIntent?.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ if (shareIntent?.resolveActivity(pm) != null)
+ startActivity(
+ Intent.createChooser(
+ shareIntent,
+ context.getString(R.string.export_lesson)
+ )
+ )
}
@@ -225,7 +258,8 @@ class SegmentController(bundle: Bundle) : BaseController(bundle), SegmentView {
shareDialog.show()
}
- private fun onSegmentFavoriteClick(markdown: Markdown) = presenter.submitMarkdownFavorite(markdown)
+ private fun onSegmentFavoriteClick(markdown: Markdown) =
+ presenter.submitMarkdownFavorite(markdown)
private fun onFootClicked(position: Int) {
markdownIds?.let {
diff --git a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/SegmentDetailController.kt b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/SegmentDetailController.kt
index ab639e04..e2a0e5e8 100644
--- a/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/SegmentDetailController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/feature/segment/view/controller/SegmentDetailController.kt
@@ -15,7 +15,7 @@ import org.secfirst.umbrella.misc.launchSilent
class SegmentDetailController(bundle: Bundle) : BaseController(bundle) {
- private val markdown by lazy { args.getParcelable(EXTRA_SELECTED_SEGMENT_DETAIL) as Markdown }
+ private val markdown by lazy { args.getParcelable(EXTRA_SELECTED_SEGMENT_DETAIL) as Markdown? }
override fun onInject() {}
@@ -33,10 +33,10 @@ class SegmentDetailController(bundle: Bundle) : BaseController(bundle) {
val css = Github()
css.addRule("body", "line-height: 1.6", "padding: 0px")
view.markdownView.addStyleSheet(css)
- launchSilent(uiContext) { view.markdownView.loadMarkdown(markdown.text) }
+ launchSilent(uiContext) { view.markdownView.loadMarkdown(markdown?.text) }
}
- fun getTitle() = markdown.title
+ fun getTitle() = markdown?.title
companion object {
const val EXTRA_SELECTED_SEGMENT_DETAIL = "selected_segment_detail"
diff --git a/app/src/main/java/org/secfirst/umbrella/misc/AboutController.kt b/app/src/main/java/org/secfirst/umbrella/misc/AboutController.kt
index 3a2c5d95..e959ff2b 100644
--- a/app/src/main/java/org/secfirst/umbrella/misc/AboutController.kt
+++ b/app/src/main/java/org/secfirst/umbrella/misc/AboutController.kt
@@ -12,7 +12,7 @@ import org.secfirst.umbrella.feature.base.view.BaseController
class AboutController(bundle: Bundle) : BaseController(bundle) {
- private val markdown by lazy { args.getParcelable(EXTRA_ABOUT) as Markdown }
+ private val markdown by lazy { args.getParcelable(EXTRA_ABOUT) as Markdown? }
constructor(markdown: Markdown) : this(Bundle().apply {
putParcelable(EXTRA_ABOUT, markdown)
@@ -29,7 +29,7 @@ class AboutController(bundle: Bundle) : BaseController(bundle) {
override fun onAttach(view: View) {
super.onAttach(view)
aboutMarkdownView.addStyleSheet(Github())
- aboutMarkdownView.loadMarkdown(markdown.text)
+ aboutMarkdownView.loadMarkdown(markdown?.text)
setUpToolbar()
}
@@ -41,7 +41,7 @@ class AboutController(bundle: Bundle) : BaseController(bundle) {
aboutToolbar?.let {
mainActivity.setSupportActionBar(it)
mainActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
- mainActivity.supportActionBar?.title = markdown.title
+ mainActivity.supportActionBar?.title = markdown?.title
}
}
}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 93160907..81f4a8df 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,14 +1,18 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.72'
+ ext.kotlin_version = '1.6.10'
repositories {
google()
+ mavenCentral()
jcenter()
+ maven {
+ url "https://oss.sonatype.org/content/repositories/snapshots"
+ }
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.3'
+ classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'org.jacoco:org.jacoco.core:0.8.1'
+ classpath 'org.jacoco:org.jacoco.core:0.8.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
@@ -23,6 +27,7 @@ plugins {
allprojects {
repositories {
google()
+ mavenCentral()
jcenter()
maven { url "https://repo.eclipse.org/content/groups/releases/" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
@@ -51,18 +56,18 @@ detekt {
ext {
- minSdkVersion = 15
- targetSdkVersion = 28
- compileSdkVersion = 28
+ minSdkVersion = 16
+ targetSdkVersion = 31
+ compileSdkVersion = 31
buildToolsVersion = '26.0.2'
support_library_version = '28.0.0'
support_constraint_version = '1.1.3'
- dagger2_version = '2.27'
+ dagger2_version = '2.41'
runner_version = '1.0.2'
espresso_version = '3.0.2'
espresso_descendant_actions = '1.4.0'
- junit_version = '4.13'
+ junit_version = '4.13.2'
rx_android_version = '2.0.2'
rx_java_version = '2.1.14'
retrofit_version = '2.8.1'
@@ -75,18 +80,17 @@ ext {
okHttpLog_version = '3.9.1'
jgit_version = '3.7.1.201504261725-r'
commonsIo_version = '2.6'
- jackson_databind_version = '2.11.0'
- jackson_yaml_version = '2.11.0'
- jackson_module_version = '2.11.0'
+ jackson_databind_version = '2.11.1'
+ jackson_yaml_version = '2.11.1'
+ jackson_module_version = '2.11.1'
hamcrest_core_version = '2.2'
hamcrest_version = '2.2'
test_support_version = '0.1'
test_rule_version = '1.0.2'
mockito_version = '3.3.3'
- junit_version = '4.12'
- coroutine_version = "1.3.5"
- conductor_version = "3.0.0-rc4"
- conductor_version_support = "3.0.0-rc2"
+ coroutine_version = "1.4.1"
+ conductor_version = "3.1.4"
+ conductor_version_support = "3.1.4"
stepper_version = "4.3.1"
multidex_version = "2.0.1"
jsoup = '1.13.1'
diff --git a/gradle.properties b/gradle.properties
index 58be69cb..80c63ab2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,4 +15,4 @@ org.gradle.jvmargs=-Xmx1536m
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useAndroidX=true
-android.enableJetifier=true
+android.enableJetifier=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0374c08f..16efe4b4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip