pachli-android/plugins/markdown2resource
Nik Clayton e749b362ca
refactor: Start creating core modules (#286)
The existing code base is a single monolithic module. This is relatively
simple to configure, but many of the tasks to compile the module and
produce the final app have to run in series.

This is unnecessarily slow.

This change starts to split the code in to multiple modules, which are:

- :core:account - AccountManager, to break a dependency cycle
- :core:common - low level types or utilities used in many other modules
- :core:database - database types, DAOs, and DI infrastructure
- :core:network - network types, API definitions, and DI infrastructure
- :core:preferences - shared preferences definitions and DI
infrastructure
- :core:testing - fakes and rules used across different modules

Benchmarking with gradle-profiler shows a ~ 17% reduction in incremental
build times after an ABI change. That will improve further as more code
is moved to modules.

The rough mechanics of the changes are:

- Create the modules, and move existing files in to them. This causes a
  lot of churn in import arguments.

- Convert build.gradle files to build.gradle.kts

- Separate out the data required to display a tab (`TabViewData`) from
  the data required to configure a tab (`TabData`) to avoid circular
  dependencies.

- Abstract the repeated build logic shared between the modules in to
  a set of plugins under `build-logic/`, to simplify configuration of
  the application and library builds.

- Be explicit that some nullable types are non-null at time of use.
  Nullable properties in types imported from modules generally can't be
  smart cast to non-null. There's a detailed discussion of why this
restriction exists at
https://discuss.kotlinlang.org/t/what-is-the-reason-behind-smart-cast-being-impossible-to-perform-when-referenced-class-is-in-another-module/2201.

The changes highlight design problems with the current code, including:

- The main application code is too tightly coupled to the network types
- Too many values are declared unnecessarily nullable
- Dependency cycles between code that make modularisation difficult

Future changes will add more modules.

See #291.
2023-12-04 16:58:36 +01:00
..
src/main/kotlin/app/pachli/plugins/markdown2resource feat: Embed the privacy policy in the app (#139) 2023-10-03 12:56:30 +02:00
README.md feat: Embed the privacy policy in the app (#139) 2023-10-03 12:56:30 +02:00
build.gradle.kts refactor: Start creating core modules (#286) 2023-12-04 16:58:36 +01:00
gradle.properties refactor: Start creating core modules (#286) 2023-12-04 16:58:36 +01:00
settings.gradle.kts refactor: Start creating core modules (#286) 2023-12-04 16:58:36 +01:00

README.md

markdown2resource-plugin

Synopsis

Gradle plugin to convert one or more Markdown files to Java files with static constants where the Markdown has been converted to HTML. Similar (but not quite identical) to Android resources.

Example

In build.gradle:

// Install the plugin
plugins {
    id "app.pachli.plugins.markdown2resource"
}

// ...

// Configure the files to be processed
markdown2resource {
    files = [ layout.projectDirectory.file('../PRIVACY.md') ]
}

In code:

// Assume binding.privacyPolicy references a `WebView`

// The generated string constant is in the `markdownR.html` package, named
// `PRIVACY_md`. To load the content in to a WebView it must be converted to
// base64
val html = Base64.encodeToString(markdownR.html.PRIVACY_md.toByteArray(), Base64.NO_PADDING)
binding.privacyPolicy.loadData(html, "text/html", "base64")

Configuration

The markdown2resource block supports the following options.

files - a list of RegularFile in Markdown.

packageName - the package name to use for the generated resources. Default is the android.namespace of the build variant.

resourceClassName - the outer class name to use for the generated resources. Default is markdownR.

stringClassName - the inner class name to use for the generated resources. Default is html.

Tasks

The plugin creates N tasks, one for each configured build variant, named markdown2resource${variant.name.capitalized()}

For example:

  1. You have defined debug and release build types, two tasks will be created, markdown2resourceDebug and markdown2resourceRelease.
  2. You have defined debug and release build types and demo and full product flavours, four tasks will be created, markdown2resourceDemoDebug, markdown2resourceDemoRelease, markdown2resourceFullDebug, markdown2resourceFullRelease.