-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #34 from sergio-sastre/release/0.4.0
0.4.0
- Loading branch information
Showing
30 changed files
with
2,716 additions
and
164 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
174 changes: 174 additions & 0 deletions
174
...n/java/sergio/sastre/composable/preview/scanner/android/device/DevicePreviewInfoParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
package sergio.sastre.composable.preview.scanner.android.device | ||
|
||
import sergio.sastre.composable.preview.scanner.android.device.domain.Cutout | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Cutout.NONE | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Device | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Dimensions | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Navigation.GESTURE | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Orientation.LANDSCAPE | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Orientation.PORTRAIT | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.GetDeviceByIdentifier.Companion.findByDeviceId | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.GetDeviceByIdentifier.Companion.findByDeviceName | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Navigation | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Orientation | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Shape | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Type | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Unit | ||
import sergio.sastre.composable.preview.scanner.android.device.types.DEFAULT | ||
import sergio.sastre.composable.preview.scanner.android.device.types.Automotive | ||
import sergio.sastre.composable.preview.scanner.android.device.types.Desktop | ||
import sergio.sastre.composable.preview.scanner.android.device.types.GenericDevices | ||
import sergio.sastre.composable.preview.scanner.android.device.types.Phone | ||
import sergio.sastre.composable.preview.scanner.android.device.types.Tablet | ||
import sergio.sastre.composable.preview.scanner.android.device.types.Television | ||
import sergio.sastre.composable.preview.scanner.android.device.types.Wear | ||
|
||
object DevicePreviewInfoParser { | ||
fun parse(device: String): Device? { | ||
if (device == "") return DEFAULT | ||
|
||
if (device.startsWith("spec:")) { | ||
return GetCustomDevice.from(device) | ||
} | ||
|
||
if (device.startsWith("id:")) { | ||
return GetDeviceById.from(device) | ||
} | ||
|
||
if (device.startsWith("name:")) { | ||
return GetDeviceByName.from(device) | ||
} | ||
|
||
return null | ||
} | ||
} | ||
|
||
private object GetDeviceById { | ||
fun from(device: String): Device? { | ||
val id = device.removePrefix("id:") | ||
return findByDeviceId<Phone>(id)?.device | ||
?: findByDeviceId<Tablet>(id)?.device | ||
?: findByDeviceId<Wear>(id)?.device | ||
?: findByDeviceId<Desktop>(id)?.device | ||
?: findByDeviceId<Automotive>(id)?.device | ||
?: findByDeviceId<Television>(id)?.device | ||
?: findByDeviceId<GenericDevices>(id)?.device | ||
} | ||
} | ||
|
||
private object GetDeviceByName { | ||
fun from(device: String): Device? { | ||
val name = device.removePrefix("name:") | ||
return findByDeviceName<Phone>(name)?.device | ||
?: findByDeviceName<Tablet>(name)?.device | ||
?: findByDeviceName<Wear>(name)?.device | ||
?: findByDeviceName<Desktop>(name)?.device | ||
?: findByDeviceName<Automotive>(name)?.device | ||
?: findByDeviceName<Television>(name)?.device | ||
?: findByDeviceName<GenericDevices>(name)?.device | ||
} | ||
} | ||
|
||
private object GetCustomDevice { | ||
fun from(device: String): Device { | ||
val spec = device.removePrefix("spec:") | ||
.splitToSequence(",") | ||
.map { it.split("=", limit = 2).map { value -> value.trim() } } | ||
.associateBy({ it[0] }, { it[1] }) | ||
|
||
val parent = spec["parent"] | ||
if (parent != null) { | ||
return buildDeviceFromParent( | ||
parent = parent, | ||
orientation = spec["orientation"], | ||
navigation = spec["navigation"] | ||
) | ||
} | ||
|
||
// This is deprecated... but needed for old configs | ||
val type = spec["id"] | ||
val typeValue = when (type) { | ||
"reference_desktop" -> Type.DESKTOP | ||
"reference_tablet" -> Type.TABLET | ||
"reference_phone" -> Type.PHONE | ||
"reference_foldable" -> Type.FOLDABLE | ||
else -> null | ||
} | ||
|
||
val dimensions = dimensions(spec) | ||
|
||
val roundShape = (spec["isRound"]?.toBoolean() ?: spec["shape"]?.equals("Round")) | ||
val roundShapeValue = when (roundShape) { | ||
true -> Shape.ROUND | ||
false -> Shape.NOTROUND | ||
null -> Shape.NOTROUND | ||
} | ||
|
||
val dpiValue = spec["dpi"]?.toIntOrNull() ?: 420 | ||
|
||
val orientation = spec["orientation"] | ||
val orientationValue = | ||
orientation?.let { Orientation.entries.find { it.value == orientation } } | ||
?: if (dimensions.height >= dimensions.width) PORTRAIT else LANDSCAPE | ||
|
||
val chinSize = spec["chinSize"]?.removeSuffix("dp")?.toIntOrNull() ?: 0 | ||
|
||
val navigation = spec["navigation"] | ||
val navigationValue = | ||
navigation?.let { Navigation.entries.find { it.value == navigation } } ?: GESTURE | ||
|
||
val cutout = spec["cutout"] | ||
val cutoutValue = cutout?.let { Cutout.entries.find { it.value == cutout } } ?: NONE | ||
|
||
return Device( | ||
dimensions = dimensions, | ||
shape = roundShapeValue, | ||
densityDpi = dpiValue, | ||
type = typeValue, | ||
orientation = orientationValue, | ||
chinSize = chinSize, | ||
navigation = navigationValue, | ||
cutout = cutoutValue, | ||
) | ||
} | ||
|
||
private fun buildDeviceFromParent( | ||
parent: String, | ||
orientation: String?, | ||
navigation: String?, | ||
): Device { | ||
val parentDevice = requireNotNull(GetDeviceById.from(parent)) | ||
val orientationValue = orientation?.let { | ||
Orientation.entries.find { it.value == orientation } | ||
} ?: parentDevice.orientation | ||
|
||
val navigationValue = navigation?.let { | ||
Navigation.entries.find { it.value == navigation } | ||
} ?: parentDevice.navigation | ||
|
||
return parentDevice.copy(orientation = orientationValue, navigation = navigationValue) | ||
} | ||
|
||
private fun dimensions(spec: Map<String, String>): Dimensions { | ||
val screenHeight = spec["height"] | ||
val heightValue: Float = | ||
screenHeight?.removeSuffix("dp")?.removeSuffix("px")?.toFloatOrNull() | ||
?: throw IllegalArgumentException("height can never be null") | ||
|
||
val screenWidth = spec["width"] | ||
val widthValue: Float = | ||
screenWidth?.removeSuffix("dp")?.removeSuffix("px")?.toFloatOrNull() | ||
?: throw IllegalArgumentException("width can never be null") | ||
|
||
val unit = spec["unit"] ?: spec["height"]?.takeLast(2) ?: spec["width"]?.takeLast(2) | ||
val unitValue: Unit = | ||
unit?.let { Unit.entries.find { it.value == unit } } | ||
?: throw IllegalArgumentException("unit can never be null") | ||
|
||
return Dimensions( | ||
height = heightValue, | ||
width = widthValue, | ||
unit = unitValue | ||
) | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
...id/src/main/java/sergio/sastre/composable/preview/scanner/android/device/domain/Device.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package sergio.sastre.composable.preview.scanner.android.device.domain | ||
|
||
import sergio.sastre.composable.preview.scanner.android.device.domain.Cutout.NONE | ||
import sergio.sastre.composable.preview.scanner.android.device.domain.Navigation.GESTURE | ||
import kotlin.math.ceil | ||
import kotlin.math.floor | ||
|
||
data class Device( | ||
val identifier: Identifier? = null, | ||
val dimensions: Dimensions, | ||
val densityDpi: Int, | ||
val orientation: Orientation, | ||
val shape: Shape, | ||
val chinSize: Int = 0, | ||
val type: Type? = null, | ||
val screenRatio: ScreenRatio = ScreenRatioCalculator.calculateFor(dimensions), | ||
val screenSize: ScreenSize = ScreenSizeCalculator.calculateFor(dimensions, densityDpi), | ||
val cutout: Cutout = NONE, | ||
val navigation: Navigation = GESTURE, | ||
) { | ||
|
||
fun inDp(): Device = this.copy(dimensions = dimensions.inDp(densityDpi)) | ||
|
||
fun inPx(): Device = this.copy(dimensions = dimensions.inPx(densityDpi)) | ||
} | ||
|
||
class Dimensions( | ||
val height: Float, | ||
val width: Float, | ||
val unit: Unit, | ||
) { | ||
fun inDp(densityDpi: Int): Dimensions { | ||
val conversionFactor: Float = densityDpi / 160f | ||
return when (unit) { | ||
Unit.DP -> this | ||
Unit.PX -> Dimensions( | ||
height = floor(height / conversionFactor), | ||
width = floor(width / conversionFactor), | ||
unit = Unit.DP | ||
) | ||
} | ||
} | ||
|
||
fun inPx(densityDpi: Int): Dimensions { | ||
val conversionFactor: Float = densityDpi / 160f | ||
return when (unit) { | ||
Unit.PX -> this | ||
Unit.DP -> | ||
Dimensions( | ||
height = ceil(height * conversionFactor), | ||
width = ceil(width * conversionFactor), | ||
unit = Unit.DP | ||
) | ||
} | ||
} | ||
} | ||
|
||
enum class Unit(val value: String) { | ||
DP("dp"), | ||
PX("px") | ||
} | ||
|
||
enum class Shape { ROUND, NOTROUND } | ||
|
||
enum class ScreenRatio { LONG, NOTLONG } | ||
|
||
enum class ScreenSize { SMALL, NORMAL, LARGE, XLARGE } | ||
|
||
enum class Orientation(val value: String) { | ||
PORTRAIT("portrait"), | ||
LANDSCAPE("landscape") | ||
} | ||
|
||
enum class Cutout(val value: String) { | ||
NONE("none"), | ||
CORNER("corner"), | ||
DOUBLE("double"), | ||
PUNCH_HOLE("punch_hole"), | ||
TALL("tall") | ||
} | ||
|
||
enum class Navigation(val value: String) { | ||
GESTURE("gesture"), | ||
BUTTONS("buttons") | ||
} | ||
|
||
enum class Type { PHONE, TABLET, DESKTOP, FOLDABLE, WEAR, CAR, TV } |
Oops, something went wrong.