@react-navigation/native 8.0.0-alpha.0 → 8.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ReactNavigation.podspec +20 -0
- package/android/build.gradle +147 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/org/reactnavigation/MaterialSymbolModule.kt +100 -0
- package/android/src/main/java/org/reactnavigation/MaterialSymbolTypeface.kt +77 -0
- package/android/src/main/java/org/reactnavigation/MaterialSymbolView.kt +95 -0
- package/android/src/main/java/org/reactnavigation/MaterialSymbolViewManager.kt +49 -0
- package/android/src/main/java/org/reactnavigation/ReactNavigationPackage.kt +34 -0
- package/assets/fonts/MaterialSymbolsOutlined.codepoints +4102 -0
- package/assets/fonts/MaterialSymbolsOutlined_100.ttf +0 -0
- package/assets/fonts/MaterialSymbolsOutlined_200.ttf +0 -0
- package/assets/fonts/MaterialSymbolsOutlined_300.ttf +0 -0
- package/assets/fonts/MaterialSymbolsOutlined_400.ttf +0 -0
- package/assets/fonts/MaterialSymbolsOutlined_500.ttf +0 -0
- package/assets/fonts/MaterialSymbolsOutlined_600.ttf +0 -0
- package/assets/fonts/MaterialSymbolsOutlined_700.ttf +0 -0
- package/assets/fonts/MaterialSymbolsRounded.codepoints +4102 -0
- package/assets/fonts/MaterialSymbolsRounded_100.ttf +0 -0
- package/assets/fonts/MaterialSymbolsRounded_200.ttf +0 -0
- package/assets/fonts/MaterialSymbolsRounded_300.ttf +0 -0
- package/assets/fonts/MaterialSymbolsRounded_400.ttf +0 -0
- package/assets/fonts/MaterialSymbolsRounded_500.ttf +0 -0
- package/assets/fonts/MaterialSymbolsRounded_600.ttf +0 -0
- package/assets/fonts/MaterialSymbolsRounded_700.ttf +0 -0
- package/assets/fonts/MaterialSymbolsSharp.codepoints +4102 -0
- package/assets/fonts/MaterialSymbolsSharp_100.ttf +0 -0
- package/assets/fonts/MaterialSymbolsSharp_200.ttf +0 -0
- package/assets/fonts/MaterialSymbolsSharp_300.ttf +0 -0
- package/assets/fonts/MaterialSymbolsSharp_400.ttf +0 -0
- package/assets/fonts/MaterialSymbolsSharp_500.ttf +0 -0
- package/assets/fonts/MaterialSymbolsSharp_600.ttf +0 -0
- package/assets/fonts/MaterialSymbolsSharp_700.ttf +0 -0
- package/ios/ReactNavigationSFSymbolView.h +14 -0
- package/ios/ReactNavigationSFSymbolView.mm +79 -0
- package/ios/ReactNavigationSFSymbolView.swift +300 -0
- package/lib/module/NavigationContainer.js +7 -2
- package/lib/module/NavigationContainer.js.map +1 -1
- package/lib/module/createStaticNavigation.js +3 -6
- package/lib/module/createStaticNavigation.js.map +1 -1
- package/lib/module/index.js +4 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/native/MaterialSymbol.android.js +58 -0
- package/lib/module/native/MaterialSymbol.android.js.map +1 -0
- package/lib/module/native/MaterialSymbol.js +9 -0
- package/lib/module/native/MaterialSymbol.js.map +1 -0
- package/lib/module/native/MaterialSymbolData.js +2 -0
- package/lib/module/native/MaterialSymbolData.js.map +1 -0
- package/lib/module/native/MaterialSymbolViewNativeComponent.ts +23 -0
- package/lib/module/native/NativeMaterialSymbolModule.js +7 -0
- package/lib/module/native/NativeMaterialSymbolModule.js.map +1 -0
- package/lib/module/native/SFSymbol.ios.js +46 -0
- package/lib/module/native/SFSymbol.ios.js.map +1 -0
- package/lib/module/native/SFSymbol.js +6 -0
- package/lib/module/native/SFSymbol.js.map +1 -0
- package/lib/module/native/SFSymbolViewNativeComponent.ts +32 -0
- package/lib/module/native/constants.js +14 -0
- package/lib/module/native/constants.js.map +1 -0
- package/lib/module/native/types.js +4 -0
- package/lib/module/native/types.js.map +1 -0
- package/lib/module/theming/{DefaultTheme.js → LightTheme.js} +2 -2
- package/lib/module/theming/LightTheme.js.map +1 -0
- package/lib/module/theming/MaterialTheme.android.js +29 -0
- package/lib/module/theming/MaterialTheme.android.js.map +1 -0
- package/lib/module/theming/MaterialTheme.js +18 -0
- package/lib/module/theming/MaterialTheme.js.map +1 -0
- package/lib/module/useLinkBuilder.js +24 -5
- package/lib/module/useLinkBuilder.js.map +1 -1
- package/lib/module/useLinkTo.js +2 -4
- package/lib/module/useLinkTo.js.map +1 -1
- package/lib/module/useLinking.native.js +20 -3
- package/lib/module/useLinking.native.js.map +1 -1
- package/lib/typescript/src/NavigationContainer.d.ts +6 -1
- package/lib/typescript/src/NavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/createStaticNavigation.d.ts +3 -3
- package/lib/typescript/src/createStaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native/MaterialSymbol.android.d.ts +8 -0
- package/lib/typescript/src/native/MaterialSymbol.android.d.ts.map +1 -0
- package/lib/typescript/src/native/MaterialSymbol.d.ts +8 -0
- package/lib/typescript/src/native/MaterialSymbol.d.ts.map +1 -0
- package/lib/typescript/src/native/MaterialSymbolData.d.ts +2 -0
- package/lib/typescript/src/native/MaterialSymbolData.d.ts.map +1 -0
- package/lib/typescript/src/native/MaterialSymbolViewNativeComponent.d.ts +11 -0
- package/lib/typescript/src/native/MaterialSymbolViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/native/NativeMaterialSymbolModule.d.ts +7 -0
- package/lib/typescript/src/native/NativeMaterialSymbolModule.d.ts.map +1 -0
- package/lib/typescript/src/native/SFSymbol.d.ts +5 -0
- package/lib/typescript/src/native/SFSymbol.d.ts.map +1 -0
- package/lib/typescript/src/native/SFSymbol.ios.d.ts +5 -0
- package/lib/typescript/src/native/SFSymbol.ios.d.ts.map +1 -0
- package/lib/typescript/src/native/SFSymbolViewNativeComponent.d.ts +23 -0
- package/lib/typescript/src/native/SFSymbolViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/native/constants.d.ts +12 -0
- package/lib/typescript/src/native/constants.d.ts.map +1 -0
- package/lib/typescript/src/native/types.d.ts +181 -0
- package/lib/typescript/src/native/types.d.ts.map +1 -0
- package/lib/typescript/src/theming/{DefaultTheme.d.ts → LightTheme.d.ts} +2 -2
- package/lib/typescript/src/theming/LightTheme.d.ts.map +1 -0
- package/lib/typescript/src/theming/MaterialTheme.android.d.ts +127 -0
- package/lib/typescript/src/theming/MaterialTheme.android.d.ts.map +1 -0
- package/lib/typescript/src/theming/MaterialTheme.d.ts +114 -0
- package/lib/typescript/src/theming/MaterialTheme.d.ts.map +1 -0
- package/lib/typescript/src/useLinkBuilder.d.ts +104 -6
- package/lib/typescript/src/useLinkBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useLinking.native.d.ts.map +1 -1
- package/package.json +39 -4
- package/src/NavigationContainer.tsx +20 -3
- package/src/createStaticNavigation.tsx +8 -12
- package/src/index.tsx +7 -1
- package/src/native/MaterialSymbol.android.tsx +83 -0
- package/src/native/MaterialSymbol.tsx +17 -0
- package/src/native/MaterialSymbolData.tsx +4106 -0
- package/src/native/MaterialSymbolViewNativeComponent.ts +23 -0
- package/src/native/NativeMaterialSymbolModule.ts +19 -0
- package/src/native/SFSymbol.ios.tsx +53 -0
- package/src/native/SFSymbol.tsx +9 -0
- package/src/native/SFSymbolViewNativeComponent.ts +32 -0
- package/src/native/constants.tsx +11 -0
- package/src/native/types.tsx +218 -0
- package/src/theming/{DefaultTheme.tsx → LightTheme.tsx} +1 -1
- package/src/theming/MaterialTheme.android.tsx +30 -0
- package/src/theming/MaterialTheme.tsx +19 -0
- package/src/useLinkBuilder.tsx +26 -6
- package/src/useLinkTo.tsx +2 -2
- package/src/useLinking.native.tsx +38 -15
- package/lib/module/theming/DefaultTheme.js.map +0 -1
- package/lib/typescript/src/theming/DefaultTheme.d.ts.map +0 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "ReactNavigation"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = "Satyajit Sahoo <satyajit.happy@gmail.com> (https://github.com/satya164/), Michał Osadnik <micosa97@gmail.com> (https://github.com/osdnk/)"
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
14
|
+
s.source = { :git => "https://github.com/react-navigation/react-navigation.git", :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
|
|
17
|
+
s.private_header_files = "ios/**/*.h"
|
|
18
|
+
|
|
19
|
+
install_modules_dependencies(s)
|
|
20
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import groovy.json.JsonSlurper
|
|
2
|
+
|
|
3
|
+
buildscript {
|
|
4
|
+
ext.ReactNavigation = [
|
|
5
|
+
kotlinVersion: "2.0.21",
|
|
6
|
+
minSdkVersion: 24,
|
|
7
|
+
compileSdkVersion: 36,
|
|
8
|
+
targetSdkVersion: 36
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
ext.getExtOrDefault = { prop ->
|
|
12
|
+
if (rootProject.ext.has(prop)) {
|
|
13
|
+
return rootProject.ext.get(prop)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return ReactNavigation[prop]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
repositories {
|
|
20
|
+
google()
|
|
21
|
+
mavenCentral()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
dependencies {
|
|
25
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
26
|
+
// noinspection DifferentKotlinGradleVersion
|
|
27
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
apply plugin: "com.android.library"
|
|
33
|
+
apply plugin: "kotlin-android"
|
|
34
|
+
|
|
35
|
+
apply plugin: "com.facebook.react"
|
|
36
|
+
|
|
37
|
+
android {
|
|
38
|
+
namespace "org.reactnavigation"
|
|
39
|
+
|
|
40
|
+
compileSdkVersion getExtOrDefault("compileSdkVersion")
|
|
41
|
+
|
|
42
|
+
defaultConfig {
|
|
43
|
+
minSdkVersion getExtOrDefault("minSdkVersion")
|
|
44
|
+
targetSdkVersion getExtOrDefault("targetSdkVersion")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
buildTypes {
|
|
48
|
+
release {
|
|
49
|
+
minifyEnabled false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
lint {
|
|
54
|
+
disable "GradleCompatible"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
compileOptions {
|
|
58
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
59
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
tasks.register('copyMaterialFonts', Copy) {
|
|
64
|
+
def packageJsonFile = file(rootDir.path + "/../package.json")
|
|
65
|
+
def fontsConfig = null
|
|
66
|
+
|
|
67
|
+
if (packageJsonFile.exists()) {
|
|
68
|
+
def packageJson = new JsonSlurper().parse(packageJsonFile)
|
|
69
|
+
|
|
70
|
+
fontsConfig = packageJson["react-navigation"]?.get("material-symbols")?.get("fonts")
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fontsConfig = fontsConfig != null ? fontsConfig : [[variant: "outlined", weights: [400]]]
|
|
74
|
+
|
|
75
|
+
def assetsFontsDir = file("../assets/fonts")
|
|
76
|
+
def availableFonts = assetsFontsDir.listFiles()
|
|
77
|
+
?.findAll { it.name.startsWith("MaterialSymbols") && it.name.endsWith(".ttf") }
|
|
78
|
+
?.collect { it.name.replaceFirst(/^MaterialSymbols/, '').replaceFirst(/\.ttf$/, '') } ?: []
|
|
79
|
+
|
|
80
|
+
def validVariants = availableFonts.collect { it.split('_')[0].toLowerCase() }.unique().sort()
|
|
81
|
+
def validWeights = availableFonts.collect { it.split('_')[1] as int }.unique().sort()
|
|
82
|
+
|
|
83
|
+
def errors = [] as Set
|
|
84
|
+
|
|
85
|
+
fontsConfig.each { font ->
|
|
86
|
+
if (font.variant && !validVariants.contains(font.variant.toLowerCase())) {
|
|
87
|
+
errors << "Invalid font variant: ${font.variant}"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
font.weights.each { weight ->
|
|
91
|
+
if (!validWeights.contains(weight)) {
|
|
92
|
+
errors << "Invalid font weight: ${weight}"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (errors) {
|
|
98
|
+
throw new GradleException(
|
|
99
|
+
errors.join("\n") + "\n\nAvailable variants: ${validVariants.join(", ")}.\nAvailable weights: ${validWeights.join(", ")}."
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
def fontFiles = fontsConfig.collectMany { font ->
|
|
104
|
+
def variant = font.variant?.capitalize() ?: ""
|
|
105
|
+
|
|
106
|
+
font.weights.collect { weight -> "MaterialSymbols${variant}_${weight}.ttf" }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (fontFiles) {
|
|
110
|
+
from(assetsFontsDir) { include fontFiles }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
into layout.buildDirectory.dir("intermediates/react-navigation/fonts")
|
|
114
|
+
|
|
115
|
+
doFirst {
|
|
116
|
+
if (destinationDir.exists()) {
|
|
117
|
+
def extraFiles = destinationDir.listFiles()?.findAll { file -> !fontFiles.contains(file.name) }
|
|
118
|
+
|
|
119
|
+
extraFiles?.each { file -> file.delete() }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
doLast {
|
|
124
|
+
def digest = java.security.MessageDigest.getInstance("MD5")
|
|
125
|
+
|
|
126
|
+
fontFiles.sort().each { name ->
|
|
127
|
+
def fontFile = new File(assetsFontsDir, name)
|
|
128
|
+
|
|
129
|
+
if (fontFile.exists()) {
|
|
130
|
+
digest.update(fontFile.bytes)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
def hash = digest.digest().encodeHex().toString().take(8)
|
|
135
|
+
def hashFile = new File(destinationDir, "MaterialSymbols.hash")
|
|
136
|
+
|
|
137
|
+
hashFile.text = hash
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
android.sourceSets.main.assets.srcDirs += layout.buildDirectory.dir("intermediates/react-navigation")
|
|
142
|
+
|
|
143
|
+
preBuild.dependsOn(copyMaterialFonts)
|
|
144
|
+
|
|
145
|
+
dependencies {
|
|
146
|
+
implementation "com.facebook.react:react-android"
|
|
147
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
package org.reactnavigation
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap
|
|
4
|
+
import android.graphics.Canvas
|
|
5
|
+
import android.graphics.Paint
|
|
6
|
+
import androidx.core.graphics.createBitmap
|
|
7
|
+
import androidx.core.net.toUri
|
|
8
|
+
import com.facebook.fbreact.specs.NativeMaterialSymbolModuleSpec
|
|
9
|
+
import com.facebook.react.bridge.ColorPropConverter
|
|
10
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
11
|
+
import com.facebook.react.bridge.ReadableMap
|
|
12
|
+
import kotlinx.coroutines.CoroutineScope
|
|
13
|
+
import kotlinx.coroutines.Dispatchers
|
|
14
|
+
import kotlinx.coroutines.SupervisorJob
|
|
15
|
+
import kotlinx.coroutines.launch
|
|
16
|
+
import java.io.File
|
|
17
|
+
import java.io.FileOutputStream
|
|
18
|
+
import kotlin.math.roundToInt
|
|
19
|
+
|
|
20
|
+
class MaterialSymbolModule(reactContext: ReactApplicationContext) :
|
|
21
|
+
NativeMaterialSymbolModuleSpec(reactContext) {
|
|
22
|
+
|
|
23
|
+
companion object {
|
|
24
|
+
const val NAME = NativeMaterialSymbolModuleSpec.NAME
|
|
25
|
+
|
|
26
|
+
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private val fontHash: String by lazy {
|
|
30
|
+
reactApplicationContext.assets.open("fonts/MaterialSymbols.hash").bufferedReader().readText()
|
|
31
|
+
.trim()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
override fun getImageSource(
|
|
35
|
+
name: String, variant: String?, weight: Double?, size: Double, color: ReadableMap
|
|
36
|
+
): String {
|
|
37
|
+
val colorValue = color.getDynamic("value").let {
|
|
38
|
+
when (it.type) {
|
|
39
|
+
com.facebook.react.bridge.ReadableType.Number -> it.asDouble()
|
|
40
|
+
com.facebook.react.bridge.ReadableType.Map -> it.asMap()
|
|
41
|
+
else -> null
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
val resolvedColor = ColorPropConverter.getColor(colorValue, reactApplicationContext)
|
|
46
|
+
?: throw IllegalArgumentException("Could not resolve color")
|
|
47
|
+
|
|
48
|
+
val density = reactApplicationContext.resources.displayMetrics.density
|
|
49
|
+
val scaledSize = (size * density).roundToInt().coerceAtLeast(1)
|
|
50
|
+
|
|
51
|
+
val (resolvedTypeface, typefaceSuffix) = MaterialSymbolTypeface.get(
|
|
52
|
+
reactApplicationContext, variant, weight?.toInt()
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
val cacheDir = File(
|
|
56
|
+
reactApplicationContext.cacheDir,
|
|
57
|
+
"react_navigation/material_symbols/$typefaceSuffix/$fontHash"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
val cacheKey = "${name.hashCode()}_${scaledSize}_$resolvedColor"
|
|
61
|
+
val cacheFile = File(cacheDir, "$cacheKey.png")
|
|
62
|
+
|
|
63
|
+
if (cacheFile.exists()) {
|
|
64
|
+
return cacheFile.toUri().toString()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
scope.launch {
|
|
68
|
+
cacheDir.parentFile?.listFiles { it.isDirectory && it.name != fontHash }
|
|
69
|
+
?.forEach { it.deleteRecursively() }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
cacheDir.mkdirs()
|
|
73
|
+
|
|
74
|
+
val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
|
75
|
+
typeface = resolvedTypeface
|
|
76
|
+
textSize = scaledSize.toFloat()
|
|
77
|
+
textAlign = Paint.Align.CENTER
|
|
78
|
+
|
|
79
|
+
this.color = resolvedColor
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
val fontMetrics = paint.fontMetrics
|
|
83
|
+
val bitmap = createBitmap(scaledSize, scaledSize)
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
val canvas = Canvas(bitmap)
|
|
87
|
+
val y = (scaledSize - (fontMetrics.descent - fontMetrics.ascent)) / 2f - fontMetrics.ascent
|
|
88
|
+
|
|
89
|
+
canvas.drawText(name, scaledSize / 2f, y, paint)
|
|
90
|
+
|
|
91
|
+
FileOutputStream(cacheFile).use {
|
|
92
|
+
bitmap.compress(Bitmap.CompressFormat.PNG, 100, it)
|
|
93
|
+
}
|
|
94
|
+
} finally {
|
|
95
|
+
bitmap.recycle()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return cacheFile.toUri().toString()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
package org.reactnavigation
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Typeface
|
|
5
|
+
|
|
6
|
+
data class MaterialSymbolTypefaceResult(val typeface: Typeface, val suffix: String)
|
|
7
|
+
|
|
8
|
+
object MaterialSymbolTypeface {
|
|
9
|
+
private val typefaces = mutableMapOf<String, Typeface>()
|
|
10
|
+
private var defaultSuffix: String? = null
|
|
11
|
+
|
|
12
|
+
fun get(context: Context, variant: String?, weight: Int?): MaterialSymbolTypefaceResult {
|
|
13
|
+
val suffix = if (variant != null && weight != null) {
|
|
14
|
+
val resolvedVariant = when (variant) {
|
|
15
|
+
"rounded" -> "Rounded"
|
|
16
|
+
"sharp" -> "Sharp"
|
|
17
|
+
else -> "Outlined"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
"${resolvedVariant}_$weight"
|
|
21
|
+
} else {
|
|
22
|
+
getDefaultSuffix(context)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
val typeface = typefaces.getOrPut(suffix) {
|
|
26
|
+
val path = "fonts/MaterialSymbols${suffix}.ttf"
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
Typeface.createFromAsset(context.assets, path)
|
|
30
|
+
} catch (e: Exception) {
|
|
31
|
+
throw RuntimeException("$path not found.", e)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return MaterialSymbolTypefaceResult(typeface, suffix)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private fun getDefaultSuffix(context: Context): String {
|
|
39
|
+
defaultSuffix?.let { return it }
|
|
40
|
+
|
|
41
|
+
val fonts = context.assets.list("fonts")
|
|
42
|
+
?.filter { it.startsWith("MaterialSymbols") && it.endsWith(".ttf") } ?: emptyList()
|
|
43
|
+
|
|
44
|
+
if (fonts.isEmpty()) {
|
|
45
|
+
throw RuntimeException("No MaterialSymbols font found in assets.")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (fonts.size > 1) {
|
|
49
|
+
val outlinedFonts = fonts.filter { it.startsWith("MaterialSymbolsOutlined") }
|
|
50
|
+
val outlinedFont = when {
|
|
51
|
+
outlinedFonts.isEmpty() -> null
|
|
52
|
+
outlinedFonts.size == 1 -> outlinedFonts[0]
|
|
53
|
+
else -> outlinedFonts.firstOrNull {
|
|
54
|
+
it.removePrefix("MaterialSymbols").removeSuffix(".ttf") == "Outlined_400"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (outlinedFont == null) {
|
|
59
|
+
throw RuntimeException(
|
|
60
|
+
"Multiple MaterialSymbols fonts found in assets: ${fonts.joinToString()}. " + "Please specify a variant and weight explicitly."
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
val outlinedSuffix = outlinedFont.removePrefix("MaterialSymbols").removeSuffix(".ttf")
|
|
65
|
+
|
|
66
|
+
defaultSuffix = outlinedSuffix
|
|
67
|
+
|
|
68
|
+
return outlinedSuffix
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
val suffix = fonts[0].removePrefix("MaterialSymbols").removeSuffix(".ttf")
|
|
72
|
+
|
|
73
|
+
defaultSuffix = suffix
|
|
74
|
+
|
|
75
|
+
return suffix
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
package org.reactnavigation
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Canvas
|
|
5
|
+
import android.graphics.Paint
|
|
6
|
+
import android.util.AttributeSet
|
|
7
|
+
|
|
8
|
+
class MaterialSymbolView @JvmOverloads constructor(
|
|
9
|
+
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
|
10
|
+
) : androidx.appcompat.widget.AppCompatTextView(context, attrs, defStyleAttr) {
|
|
11
|
+
|
|
12
|
+
private var variant: String? = null
|
|
13
|
+
private var weight: Int? = null
|
|
14
|
+
|
|
15
|
+
init {
|
|
16
|
+
setColor(null)
|
|
17
|
+
updateTypeface()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override fun onDraw(canvas: Canvas) {
|
|
21
|
+
val text = text?.toString() ?: return
|
|
22
|
+
|
|
23
|
+
paint.color = currentTextColor
|
|
24
|
+
paint.textAlign = Paint.Align.CENTER
|
|
25
|
+
|
|
26
|
+
val fontMetrics = paint.fontMetrics
|
|
27
|
+
val x = width / 2f
|
|
28
|
+
val y = (height - (fontMetrics.descent - fontMetrics.ascent)) / 2f - fontMetrics.ascent
|
|
29
|
+
|
|
30
|
+
canvas.drawText(text, x, y, paint)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fun setName(name: String?) {
|
|
34
|
+
text = name
|
|
35
|
+
|
|
36
|
+
invalidate()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fun setVariant(variant: String?) {
|
|
40
|
+
if (this.variant == variant) {
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.variant = variant
|
|
45
|
+
|
|
46
|
+
updateTypeface()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fun setWeight(weight: Int?) {
|
|
50
|
+
if (this.weight == weight) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.weight = weight
|
|
55
|
+
|
|
56
|
+
updateTypeface()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private fun updateTypeface() {
|
|
60
|
+
setTypeface(
|
|
61
|
+
MaterialSymbolTypeface.get(
|
|
62
|
+
context,
|
|
63
|
+
variant?.ifEmpty { null },
|
|
64
|
+
weight.takeIf { it != 0 }).typeface
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
invalidate()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fun setColor(color: Int?) {
|
|
71
|
+
if (color == null) {
|
|
72
|
+
val typedValue = android.util.TypedValue()
|
|
73
|
+
|
|
74
|
+
context.theme.resolveAttribute(
|
|
75
|
+
android.R.attr.colorForeground, typedValue, true
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
val resolvedColor = if (typedValue.resourceId != 0) {
|
|
79
|
+
context.getColor(typedValue.resourceId)
|
|
80
|
+
} else {
|
|
81
|
+
typedValue.data
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
setTextColor(resolvedColor)
|
|
85
|
+
} else {
|
|
86
|
+
setTextColor(color)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
invalidate()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fun setSize(size: Float) {
|
|
93
|
+
textSize = size
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
package org.reactnavigation
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
4
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
5
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
6
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
7
|
+
import com.facebook.react.viewmanagers.ReactNavigationMaterialSymbolViewManagerInterface
|
|
8
|
+
|
|
9
|
+
@ReactModule(name = MaterialSymbolViewManager.NAME)
|
|
10
|
+
class MaterialSymbolViewManager : SimpleViewManager<MaterialSymbolView>(),
|
|
11
|
+
ReactNavigationMaterialSymbolViewManagerInterface<MaterialSymbolView> {
|
|
12
|
+
|
|
13
|
+
override fun getName(): String {
|
|
14
|
+
return NAME
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
override fun createViewInstance(context: ThemedReactContext): MaterialSymbolView {
|
|
18
|
+
return MaterialSymbolView(context)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@ReactProp(name = "name")
|
|
22
|
+
override fun setName(view: MaterialSymbolView, name: String?) {
|
|
23
|
+
view.setName(name)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@ReactProp(name = "variant")
|
|
27
|
+
override fun setVariant(view: MaterialSymbolView, variant: String?) {
|
|
28
|
+
view.setVariant(variant)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@ReactProp(name = "weight")
|
|
32
|
+
override fun setWeight(view: MaterialSymbolView, weight: Int?) {
|
|
33
|
+
view.setWeight(weight)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@ReactProp(name = "size")
|
|
37
|
+
override fun setSize(view: MaterialSymbolView, size: Float) {
|
|
38
|
+
view.setSize(size)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@ReactProp(name = "color", customType = "Color")
|
|
42
|
+
override fun setColor(view: MaterialSymbolView, color: Int?) {
|
|
43
|
+
view.setColor(color)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
companion object {
|
|
47
|
+
const val NAME = "ReactNavigationMaterialSymbolView"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
package org.reactnavigation
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
8
|
+
import com.facebook.react.uimanager.ViewManager
|
|
9
|
+
|
|
10
|
+
class ReactNavigationPackage : BaseReactPackage() {
|
|
11
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
12
|
+
return listOf(MaterialSymbolViewManager())
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
16
|
+
return when (name) {
|
|
17
|
+
MaterialSymbolModule.NAME -> MaterialSymbolModule(reactContext)
|
|
18
|
+
else -> null
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
|
|
23
|
+
mapOf(
|
|
24
|
+
MaterialSymbolModule.NAME to ReactModuleInfo(
|
|
25
|
+
name = MaterialSymbolModule.NAME,
|
|
26
|
+
className = MaterialSymbolModule.NAME,
|
|
27
|
+
canOverrideExistingModule = false,
|
|
28
|
+
needsEagerInit = false,
|
|
29
|
+
isCxxModule = false,
|
|
30
|
+
isTurboModule = true
|
|
31
|
+
)
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
}
|