Skip to content

Commit

Permalink
Merge pull request #166 from erdo/next-version
Browse files Browse the repository at this point in the history
Next version
  • Loading branch information
erdo committed Oct 7, 2023
2 parents a96f85a + 00dd100 commit 5638788
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 46 deletions.
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ jobs:
build:
working_directory: ~/code
docker:
- image: cimg/android:2023.05
- image: cimg/android:2023.07
environment:
JVM_OPTS: -Xmx3200m
GRADLE_OPTS: -Dorg.gradle.daemon=true
Expand All @@ -12,7 +12,7 @@ jobs:
- checkout
- restore_cache:
# bump the cache version number if you want to wipe the gradle cache
key: v5-gradle-dependencies-cache
key: v6-gradle-dependencies-cache
# - run:
# name: Chmod permissions #if permission for Gradlew Dependencies fail, use this.
# command: sudo chmod +x ./gradlew
Expand All @@ -22,7 +22,7 @@ jobs:
- save_cache:
paths:
- ~/.gradle
key: v5-gradle-dependencies-cache
key: v6-gradle-dependencies-cache

- run:
name: Run Tests fore-jv-android
Expand Down
2 changes: 1 addition & 1 deletion app-examples/example-jv-06db/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ println("[$appId testBuildType:${getTestBuildType()}]")

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(11))
languageVersion.set(JavaLanguageVersion.of(Shared.Versions.jvm_toolchain))
}
}

Expand Down
4 changes: 2 additions & 2 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ dependencies {

// we want the kotlin and android gradle plugin, because we want to access them in our plugin
//implementation("com.android.tools.build:gradle:${co.early.fore.Shared.Versions.android_gradle_plugin}")
implementation("com.android.tools.build:gradle:8.0.1")
implementation("com.android.tools.build:gradle:8.1.1")
//implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${co.early.fore.Shared.Versions.kotlin_version}")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0")

//for custom plugins
implementation(gradleApi())
Expand Down
20 changes: 10 additions & 10 deletions buildSrc/src/main/java/co/early/fore/Shared.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ object Shared {
object Android {
const val minSdk = 16
const val minComposeSdk = 21
const val compileSdk = 33
const val targetSdk = 33
const val compileSdk = 34
const val targetSdk = 34
}

object Versions {
// fore core package dependencies
const val android_gradle_plugin = "8.0.1" // must manually change buildSrc.build version
const val kotlin_version = "1.8.22" // must manually change buildSrc.build version
const val android_gradle_plugin = "8.1.1" // must manually change buildSrc.build version
const val kotlin_version = "1.9.0" // must manually change buildSrc.build version
const val kotlinx_coroutines_core = "1.7.1"
const val jvm_toolchain = 8
// fore optional package dependencies
Expand All @@ -29,9 +29,9 @@ object Shared {
const val apollo = "2.5.14"
const val apollo3 = "3.8.1"
const val retrofit = "2.9.0"
const val composeCompiler = "1.4.8" // https://developer.android.com/jetpack/androidx/releases/compose-kotlin
const val composeUi = "1.4.3"
const val androidWindow = "1.1.0-rc01"
const val composeCompiler = "1.5.0" // https://developer.android.com/jetpack/androidx/releases/compose-kotlin
const val composeUi = "1.5.1"
const val androidWindow = "1.1.0"
// example app and test dependencies
const val activityCompose = "1.4.0"
const val composeBom = "2023.05.01"
Expand Down Expand Up @@ -67,8 +67,8 @@ object Shared {
}

object Publish {
const val LIB_VERSION_NAME = "1.6.0" //"x.x.x-SNAPSHOT"
const val LIB_VERSION_CODE = 94
const val LIB_VERSION_NAME = "1.6.1" //"x.x.x-SNAPSHOT"
const val LIB_VERSION_CODE = 95
const val LIB_GROUP = "co.early.fore"
const val PROJ_NAME = "fore"
const val LIB_DEVELOPER_ID = "erdo"
Expand All @@ -82,7 +82,7 @@ object Shared {
const val LICENCE_URL = "http://www.apache.org/licenses/LICENSE-2.0.txt"

const val use_published_version = false
const val published_fore_version_for_examples = "1.6.0"
const val published_fore_version_for_examples = "1.6.1"
}

object Secrets {
Expand Down
10 changes: 5 additions & 5 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![license-apache2](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://github.com/erdo/android-fore/blob/master/LICENSE.txt){: .float-left}

![central-1.6.0](https://img.shields.io/badge/central-1.6.0-green.svg){: .float-left}
![central-1.6.1](https://img.shields.io/badge/central-1.6.1-green.svg){: .float-left}

![api-16](https://img.shields.io/badge/api-16%2B-orange.svg){: .float-left}

Expand All @@ -14,7 +14,7 @@
**fore** helps you move code out of the view layer, leaving your reactive view code to deal with the absolute fundamentals: *what things look like*

```
implementation("co.early.fore:fore-kt-android:1.6.0")
implementation("co.early.fore:fore-kt-android:1.6.1")
```

More detailed [version / package information here](https://erdo.github.io/android-fore/06-upgrading.html#shoom).
Expand All @@ -23,7 +23,7 @@ More detailed [version / package information here](https://erdo.github.io/androi

For fore's [observeAsState()](https://dev.to/erdo/tic-tac-toe-from-mvp-to-jetpack-compose-57d8) function, and fore's [WindowSize](https://dev.to/erdo/jetpack-compose-and-windowsize-classes-gb4) classes (from 1.4.0 and above):
```
implementation("co.early.fore:fore-kt-android-compose:1.4.8")
implementation("co.early.fore:fore-kt-android-compose:1.5.0")
```
(The versioning matches the composeCompiler version, but the versions are interchangeable)

Expand All @@ -33,9 +33,9 @@ The main principle behind **fore**: *drive your app by observing state*

This works well with UDF style apps or clean architecture for example, and with modern reactive UI frameworks like Compose, observing state becomes even more natural.

Diving straight into **fore** is unlikely to be optimal without first being clear about the practical differences between _state driven_ and _event driven_ code. Many legacy apps drive their UIs primarily from events (or state _changes_: state changes being analogous to events). The UI layer code often has a sequence to it: show spinner, hide spinner, show data.
Diving straight into **fore** is unlikely to be optimal without first being clear about the practical differences between _event driven_ and _state driven_ code. Many legacy apps drive their UIs primarily from events (or state _changes_ - state changes being analogous to events). In this style of code, the UI layer often (but not always) has an explicit sequence embedded in it: show spinner -> hide spinner -> show data.

**fore** is for developers driving their UIs primarily with state alone. In this paradigm, the UI code's only job is to mirror the state of the domain (sometimes the state of the view model). It's a subtle difference. Pre-Compose it results in comically tiny UI layer code. In a Compose world it helps you take full advantage of what Compose is great at: observing state, and working out the state changes for you.
**fore** is for developers driving their UIs primarily with state alone. In this paradigm, the UI code makes no assumptions about sequencing, its only job is to mirror the state of the domain (sometimes the state of the view model). The UI represents the current truth, and nothing else. It's a subtle difference. Pre-Compose it results in comically tiny UI layer code. In a Compose world it helps you take full advantage of what Compose is great at: observing state, and working out the state _changes_ for you.

Here are a few recommended background reading articles: [compose related](https://dev.to/erdo/tic-tac-toe-from-mvp-to-jetpack-compose-57d8), [some fundamentals](https://dev.to/erdo/tutorial-spot-the-deliberate-bug-165k), [re-writing the android architecture blueprints app](https://dev.to/erdo/tutorial-android-architecture-blueprints-full-todo-app-mvo-edition-259o)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,14 @@ private fun Activity.rememberWindowMetrics(): Rect {
}
}

@Deprecated(message = "this will be removed in a future version of fore, please use WindowSize", replaceWith = ReplaceWith(expression = "WindowSize(content)", "co.early.fore.ui.size.WindowSize"))
@Composable
fun Activity.ForeWindowSize(content: @Composable () -> Unit) {
WindowSize(content)
}

@Composable
fun Activity.WindowSize(content: @Composable () -> Unit) {
CompositionLocalProvider(LocalForeWindowSize provides rememberWindowSize()) {
content()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ const val BIG_LOG = 250000
* correlate logs in the event that you have many calls being logged simultaneously
*/
class InterceptorLogging @JvmOverloads constructor(
private val logger: Logger? = null,
private val maxBodyLogCharacters: Int = 4000,
private val networkingLogSanitizer: NetworkingLogSanitizer? = null) : Interceptor {
private val logger: Logger? = null,
private val maxBodyLogCharacters: Int = 4000,
private val networkingLogSanitizer: NetworkingLogSanitizer? = null,
private val curlStyleRequests: Boolean = true,
) : Interceptor {

private val nanosFormat = DecimalFormat("#,###")
private val UTF8 = Charset.forName("UTF-8")
Expand Down Expand Up @@ -89,7 +91,8 @@ class InterceptorLogging @JvmOverloads constructor(

private fun logWarning(t: Throwable) {
if (!printedWarningAlready) {
Fore.getLogger(logger).w("No network logging available: fore doesn't recognise this version of OkHttp, or you have excluded kotlin-reflect from your dependencies. ${t.message}")
Fore.getLogger(logger)
.w("No network logging available: fore doesn't recognise this version of OkHttp, or you have excluded kotlin-reflect from your dependencies. ${t.message}")
printedWarningAlready = true
}
}
Expand All @@ -101,9 +104,15 @@ class InterceptorLogging @JvmOverloads constructor(

Fore.getLogger(logger).i(TAG + randomPostTag, String.format("HTTP %s --> %s", method, url))

if (curlStyleRequests) {
Fore.getLogger(logger)
.i(TAG + randomPostTag, String.format("curl --request %s \\", method))
Fore.getLogger(logger).i(TAG + randomPostTag, String.format(" --url '%s' \\", url))
}

networkingLogSanitizer?.let {
logHeaders(it.sanitizeHeaders(headers(request)), randomPostTag)
} ?: logHeaders(headers(request), randomPostTag)
logHeaders(it.sanitizeHeaders(headers(request)), randomPostTag, curlStyle = curlStyleRequests)
} ?: logHeaders(headers(request), randomPostTag, curlStyle = curlStyleRequests)

body(request)?.let {

Expand All @@ -115,17 +124,22 @@ class InterceptorLogging @JvmOverloads constructor(
if (isPlaintext(buffer)) {

val body = networkingLogSanitizer?.let {
truncate(networkingLogSanitizer.sanitizeBody(buffer.clone().readString(charset)))
truncate(
networkingLogSanitizer.sanitizeBody(
buffer.clone().readString(charset)
)
)
} ?: truncate(buffer.clone().readString(charset))

try {
val wrappedLines = BasicTextWrapper.wrapMonospaceText(
body.replace(",", ", "),
150
)
logLines(wrappedLines, randomPostTag)
logLines(wrappedLines, randomPostTag, curlStyle = curlStyleRequests)
} catch (oom: OutOfMemoryError) {
Fore.getLogger(logger).e("Network request was too large to format nicely, consider reducing maxBodyLogCharacters from:$maxBodyLogCharacters")
Fore.getLogger(logger)
.e("Network request was too large to format nicely, consider reducing maxBodyLogCharacters from:$maxBodyLogCharacters")
Fore.getLogger(logger).e(oom.toString())
}

Expand All @@ -137,12 +151,19 @@ class InterceptorLogging @JvmOverloads constructor(
return url to method
}

private fun logResponse(response: Response, randomPostTag: String, method: String?, url: HttpUrl?, timeTaken: Long) {
private fun logResponse(
response: Response,
randomPostTag: String,
method: String?,
url: HttpUrl?,
timeTaken: Long
) {

Fore.getLogger(logger).i(
TAG + randomPostTag,
"HTTP " + method + " <-- Server replied HTTP-${code(response)} " +
"${nanosFormat.format(timeTaken / (1000 * 1000))} ms $url")
TAG + randomPostTag,
"HTTP " + method + " <-- Server replied HTTP-${code(response)} " +
"${nanosFormat.format(timeTaken / (1000 * 1000))} ms $url"
)

networkingLogSanitizer?.let {
logHeaders(it.sanitizeHeaders(headers(response)), randomPostTag)
Expand All @@ -156,16 +177,19 @@ class InterceptorLogging @JvmOverloads constructor(
val buffer = source.buffer
if (!isPlaintext(buffer)) {
Fore.getLogger(logger).i(
TAG + randomPostTag,
" (binary body omitted)")
TAG + randomPostTag,
" (binary body omitted)"
)
} else {
if (contentLength != 0L) {
val bodyJson = truncate(buffer.clone().readString(charset))
try {
val wrappedLines = BasicTextWrapper.wrapMonospaceText(bodyJson.replace(",", ", "), 150)
val wrappedLines =
BasicTextWrapper.wrapMonospaceText(bodyJson.replace(",", ", "), 150)
logLines(wrappedLines, randomPostTag)
} catch (oom: OutOfMemoryError) {
Fore.getLogger(logger).e("Network response was too large to format nicely, consider reducing maxBodyLogCharacters from:$maxBodyLogCharacters")
Fore.getLogger(logger)
.e("Network response was too large to format nicely, consider reducing maxBodyLogCharacters from:$maxBodyLogCharacters")
Fore.getLogger(logger).e(oom.toString())
}
} else {
Expand All @@ -175,24 +199,52 @@ class InterceptorLogging @JvmOverloads constructor(
}
}

private fun logLines(wrappedLines: List<String>, rndmPostTag: String) {
for (line in wrappedLines) {
Fore.getLogger(logger).i(TAG + rndmPostTag, line)
private fun logLines(
wrappedLines: List<String>,
rndmPostTag: String,
curlStyle: Boolean = false
) {
if (curlStyle) {
wrappedLines.withIndex().forEach {
if (it.index == 0) {
Fore.getLogger(logger).i(TAG + rndmPostTag, " -d '${it.value}")
} else if (it.index == wrappedLines.size - 1) {
Fore.getLogger(logger).i(TAG + rndmPostTag, "${it.value}'")
} else {
Fore.getLogger(logger).i(TAG + rndmPostTag, it.value)
}
}
} else {
for (line in wrappedLines) {
Fore.getLogger(logger).i(TAG + rndmPostTag, line)
}
}
}

private fun truncate(potentiallyLongString: String): String {
return if (potentiallyLongString.length > maxBodyLogCharacters) {
potentiallyLongString.substring(0, maxBodyLogCharacters) + "...truncated " +
if (maxBodyLogCharacters < BIG_LOG) { "(set maxBodyLogCharacters=BIG_LOG)" } else ""
if (maxBodyLogCharacters < BIG_LOG) {
"(set maxBodyLogCharacters=BIG_LOG)"
} else ""
} else {
potentiallyLongString
}
}

private fun logHeaders(headers: Headers, randomPostTag: String) {
private fun logHeaders(headers: Headers, randomPostTag: String, curlStyle: Boolean = false) {
for (headerName in headers.names()) {
Fore.getLogger(logger).i(TAG + randomPostTag, String.format(" %s: %s", headerName, headers[headerName]))
if (curlStyle) {
Fore.getLogger(logger).i(
TAG + randomPostTag,
String.format(" --header '%s: %s' \\", headerName, headers[headerName])
)
} else {
Fore.getLogger(logger).i(
TAG + randomPostTag,
String.format(" %s: %s", headerName, headers[headerName])
)
}
}
}

Expand Down Expand Up @@ -243,11 +295,13 @@ class InterceptorLogging @JvmOverloads constructor(
private fun method(request: Request): String = call(request, "method") as String
private fun url(request: Request): HttpUrl = call(request, "url") as HttpUrl
private fun headers(request: Request): Headers = call(request, "headers") as Headers
private fun body(request: Request): RequestBody? = call(request, "body")?.let { it as RequestBody }
private fun body(request: Request): RequestBody? =
call(request, "body")?.let { it as RequestBody }

private fun code(response: Response): Int = call(response, "code") as Int
private fun headers(response: Response): Headers = call(response, "headers") as Headers
private fun body(response: Response): ResponseBody? = call(response, "body")?.let { it as ResponseBody }
private fun body(response: Response): ResponseBody? =
call(response, "body")?.let { it as ResponseBody }

private fun call(clazz: Any, name: String): Any? {
return clazz::class.members.find {
Expand Down

0 comments on commit 5638788

Please sign in to comment.