Skip to content

Commit b4e4c42

Browse files
authored
DatePicker composable added (#23)
1 parent ec14153 commit b4e4c42

File tree

59 files changed

+342
-49
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+342
-49
lines changed

README.md

Lines changed: 1 addition & 1 deletion

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,5 @@ dependencies {
8282
// Optional - Add window size utils
8383
implementation 'androidx.compose.material3.adaptive:adaptive'
8484
// Reflect API
85-
implementation 'org.jetbrains.kotlin:kotlin-reflect:1.9.23'
85+
implementation 'org.jetbrains.kotlin:kotlin-reflect:1.9.24'
8686
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package expo.modules.jetpackcomposereactnative.views.datepicker
2+
3+
import expo.modules.jetpackcomposereactnative.common.ModifierProp
4+
import expo.modules.kotlin.modules.Module
5+
import expo.modules.kotlin.modules.ModuleDefinition
6+
7+
class DatePickerModule : Module() {
8+
override fun definition() = ModuleDefinition {
9+
Name("DatePickerView")
10+
View(DatePickerView::class) {
11+
Events("onConfirm", "onDismiss")
12+
Prop("showModeToggle") { view: DatePickerView, prop: Boolean ->
13+
view.updateShowModeToggle(prop)
14+
}
15+
Prop("tonalElevation") { view: DatePickerView, prop: Int ->
16+
view.updateTonalElevation(prop)
17+
}
18+
Prop("confirmText") { view: DatePickerView, prop: String ->
19+
view.updateConfirmText(prop)
20+
}
21+
Prop("dismissText") { view: DatePickerView, prop: String ->
22+
view.updateDismissText(prop)
23+
}
24+
Prop("modifier") { view: DatePickerView, prop: ModifierProp ->
25+
view.updateModifier(prop)
26+
}
27+
}
28+
}
29+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package expo.modules.jetpackcomposereactnative.views.datepicker
2+
3+
import android.content.Context
4+
import android.view.View
5+
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
6+
import androidx.compose.material3.DatePicker
7+
import androidx.compose.material3.DatePickerDialog
8+
import androidx.compose.material3.*
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.runtime.mutableStateOf
11+
import androidx.compose.runtime.remember
12+
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.unit.dp
14+
import androidx.compose.ui.platform.ComposeView
15+
import androidx.compose.ui.viewinterop.AndroidView
16+
import expo.modules.jetpackcomposereactnative.common.ModifierProp
17+
import expo.modules.jetpackcomposereactnative.common.toModifier
18+
import expo.modules.kotlin.AppContext
19+
import expo.modules.kotlin.views.ExpoView
20+
import expo.modules.kotlin.viewevent.EventDispatcher
21+
import expo.modules.kotlin.viewevent.ViewEventCallback
22+
23+
data class DatePickerProps(
24+
var modifier: ModifierProp = emptyList(),
25+
var confirmText: String? = null,
26+
var dismissText: String? = null,
27+
var tonalElevation: Int? = null,
28+
var showModeToggle: Boolean? = null,
29+
)
30+
31+
class DatePickerView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
32+
private var props = mutableStateOf(DatePickerProps())
33+
private val onConfirm by EventDispatcher()
34+
private val onDismiss by EventDispatcher()
35+
36+
init {
37+
ComposeView(context).also {
38+
it.layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
39+
it.setContent {
40+
DatePickerComposable(
41+
props = props.value,
42+
onConfirmation = onConfirm,
43+
onDismissRequest = onDismiss
44+
)
45+
}
46+
addView(it)
47+
}
48+
}
49+
50+
fun updateShowModeToggle(showModeToggle: Boolean){
51+
props.value = props.value.copy(showModeToggle = showModeToggle)
52+
}
53+
54+
fun updateTonalElevation(tonalElevation: Int) {
55+
props.value = props.value.copy(tonalElevation = tonalElevation)
56+
}
57+
58+
fun updateConfirmText(confirmText: String) {
59+
props.value = props.value.copy(confirmText = confirmText)
60+
}
61+
62+
fun updateDismissText(dismissText: String) {
63+
props.value = props.value.copy(dismissText = dismissText)
64+
}
65+
66+
fun updateModifier(modifier: ModifierProp) {
67+
props.value = props.value.copy(modifier = modifier)
68+
}
69+
}
70+
71+
@OptIn(ExperimentalMaterial3Api::class)
72+
@Composable
73+
fun DatePickerComposable(
74+
props: DatePickerProps,
75+
onConfirmation: ViewEventCallback<Map<String, Any>>,
76+
onDismissRequest: ViewEventCallback<Map<String, Any>>
77+
) {
78+
val modifier: Modifier = props.modifier.toModifier()
79+
val datePickerState = rememberDatePickerState()
80+
81+
DatePickerDialog(
82+
onDismissRequest = {
83+
onDismissRequest(mapOf())
84+
},
85+
confirmButton = {
86+
TextButton(
87+
onClick = {
88+
onConfirmation(mapOf())
89+
}
90+
) {
91+
Text(props.confirmText ?: "OK")
92+
}
93+
},
94+
dismissButton = {
95+
TextButton(
96+
onClick = {
97+
onDismissRequest(mapOf())
98+
}
99+
) {
100+
Text(props.dismissText ?: "Cancel")
101+
}
102+
},
103+
tonalElevation = props.tonalElevation?.dp ?: AlertDialogDefaults.TonalElevation
104+
) {
105+
DatePicker(
106+
state = datePickerState,
107+
showModeToggle = props.showModeToggle ?: true,
108+
)
109+
}
110+
}

example/android/app/build.gradle

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,27 @@ apply plugin: "com.facebook.react"
44

55
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
66

7+
static def versionToNumber(major, minor, patch) {
8+
return patch * 100 + minor * 10000 + major * 1000000
9+
}
10+
11+
def getRNVersion() {
12+
def version = providers.exec {
13+
workingDir(projectDir)
14+
commandLine("node", "-e", "console.log(require('react-native/package.json').version);")
15+
}.standardOutput.asText.get().trim()
16+
17+
def coreVersion = version.split("-")[0]
18+
def (major, minor, patch) = coreVersion.tokenize('.').collect { it.toInteger() }
19+
20+
return versionToNumber(
21+
major,
22+
minor,
23+
patch
24+
)
25+
}
26+
def rnVersion = getRNVersion()
27+
728
/**
829
* This is the configuration block to customize your React Native Android app.
930
* By default you don't need to apply any configuration, just uncomment the lines you need.
@@ -20,12 +41,12 @@ react {
2041
bundleCommand = "export:embed"
2142

2243
/* Folders */
23-
// The root of your project, i.e. where "package.json" lives. Default is '../..'
24-
// root = file("../../")
25-
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
26-
// reactNativeDir = file("../../node_modules/react-native")
27-
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
28-
// codegenDir = file("../../node_modules/@react-native/codegen")
44+
// The root of your project, i.e. where "package.json" lives. Default is '..'
45+
// root = file("../")
46+
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
47+
// reactNativeDir = file("../node_modules/react-native")
48+
// The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
49+
// codegenDir = file("../node_modules/@react-native/codegen")
2950

3051
/* Variants */
3152
// The list of variants to that are debuggable. For those we're going to
@@ -58,8 +79,10 @@ react {
5879
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
5980
// hermesFlags = ["-O", "-output-source-map"]
6081

61-
/* Autolinking */
62-
autolinkLibrariesWithApp()
82+
if (rnVersion >= versionToNumber(0, 75, 0)) {
83+
/* Autolinking */
84+
autolinkLibrariesWithApp()
85+
}
6386
}
6487

6588
/**
@@ -121,9 +144,6 @@ android {
121144
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
122145
}
123146
}
124-
androidResources {
125-
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
126-
}
127147
}
128148

129149
// Apply static values from `gradle.properties` to the `android.packagingOptions`
@@ -174,3 +194,8 @@ dependencies {
174194
implementation jscFlavor
175195
}
176196
}
197+
198+
if (rnVersion < versionToNumber(0, 75, 0)) {
199+
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
200+
applyNativeModulesAppBuildGradle(project)
201+
}

example/android/app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<data android:scheme="https"/>
1212
</intent>
1313
</queries>
14-
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
14+
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme">
1515
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
1616
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
1717
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
@@ -28,5 +28,6 @@
2828
<data android:scheme="expo.modules.jetpackcomposereactnative.example"/>
2929
</intent-filter>
3030
</activity>
31+
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/>
3132
</application>
3233
</manifest>

example/android/app/src/main/java/expo/modules/jetpackcomposereactnative/example/MainApplication.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import com.facebook.react.ReactPackage
1010
import com.facebook.react.ReactHost
1111
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
1212
import com.facebook.react.defaults.DefaultReactNativeHost
13-
import com.facebook.react.soloader.OpenSourceMergedSoMapping
1413
import com.facebook.soloader.SoLoader
1514

1615
import expo.modules.ApplicationLifecycleDispatcher
@@ -22,10 +21,9 @@ class MainApplication : Application(), ReactApplication {
2221
this,
2322
object : DefaultReactNativeHost(this) {
2423
override fun getPackages(): List<ReactPackage> {
25-
val packages = PackageList(this).packages
2624
// Packages that cannot be autolinked yet can be added manually here, for example:
2725
// packages.add(new MyReactNativePackage());
28-
return packages
26+
return PackageList(this).packages
2927
}
3028

3129
override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
@@ -42,7 +40,7 @@ class MainApplication : Application(), ReactApplication {
4240

4341
override fun onCreate() {
4442
super.onCreate()
45-
SoLoader.init(this, OpenSourceMergedSoMapping)
43+
SoLoader.init(this, false)
4644
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
4745
// If you opted-in for the New Architecture, we load the native entry point for this app.
4846
load()
Binary file not shown.

0 commit comments

Comments
 (0)