@@ -6,8 +6,10 @@ import {
6
6
StyleSheet ,
7
7
TouchableOpacity ,
8
8
Platform ,
9
+ Alert ,
9
10
} from 'react-native' ;
10
11
import { Dropdown } from 'react-native-element-dropdown' ;
12
+ import NfcManager , { NfcTech , Ndef } from 'react-native-nfc-manager' ;
11
13
12
14
const OpenSpool = ( ) => {
13
15
const [ color , setColor ] = useState ( 'pink' ) ;
@@ -16,13 +18,13 @@ const OpenSpool = () => {
16
18
const [ maxTemp , setMaxTemp ] = useState ( '210' ) ;
17
19
18
20
const colors = [
19
- { label : 'Pink' , value : 'pink' , hex : '# ea338d' } ,
20
- { label : 'Black' , value : 'black' , hex : '# 000000' } ,
21
- { label : 'White' , value : 'white' , hex : '#FFFFFF ' } ,
22
- { label : 'Yellow' , value : 'yellow' , hex : '# FFEB3B' } ,
23
- { label : 'Red' , value : 'red' , hex : '#F44336 ' } ,
24
- { label : 'Blue' , value : 'blue' , hex : '# 2196F3' } ,
25
- { label : 'Green' , value : 'green' , hex : '# 4CAF50' } ,
21
+ { label : 'Pink' , value : 'pink' , hex : 'ea338d' } ,
22
+ { label : 'Black' , value : 'black' , hex : '000000' } ,
23
+ { label : 'White' , value : 'white' , hex : 'ffffff ' } ,
24
+ { label : 'Yellow' , value : 'yellow' , hex : 'FFEB3B' } ,
25
+ { label : 'Red' , value : 'red' , hex : 'f95d73 ' } ,
26
+ { label : 'Blue' , value : 'blue' , hex : '2196F3' } ,
27
+ { label : 'Green' , value : 'green' , hex : '4CAF50' } ,
26
28
] ;
27
29
28
30
const types = [
@@ -33,28 +35,103 @@ const OpenSpool = () => {
33
35
{ label : 'Nylon' , value : 'nylon' } ,
34
36
] ;
35
37
36
- const temperatures = Array . from ( { length : 11 } , ( _ , i ) => ( {
38
+ const temperatures = Array . from ( { length : 20 } , ( _ , i ) => ( {
37
39
label : `${ 180 + i * 5 } °C` ,
38
- value : ( 180 + i * 5 ) . toString ( )
40
+ value : ( 180 + i * 5 ) . toString ( ) ,
39
41
} ) ) ;
40
42
41
- const handleReadTag = ( ) => {
42
- console . log ( 'Reading NFC tag...' ) ;
43
- } ;
44
-
45
- const handleWriteTag = ( ) => {
46
- console . log ( 'Writing to NFC tag...' ) ;
47
- } ;
48
-
49
- const renderColorItem = ( item ) => {
43
+ const renderColorItem = ( item : any ) => {
50
44
return (
51
45
< View style = { styles . colorItem } >
52
- < View style = { [ styles . colorSwatch , { backgroundColor : item . hex } ] } />
46
+ < View style = { [ styles . colorSwatch , { backgroundColor : `# ${ item . hex } ` } ] } />
53
47
< Text style = { styles . colorLabel } > { item . label } </ Text >
54
48
</ View >
55
49
) ;
56
50
} ;
57
51
52
+ const verifyAndSetMinTemp = ( temp : string ) => {
53
+ if ( Number ( temp ) >= Number ( maxTemp ) ) {
54
+ Alert . alert ( 'Min temperature must be less than max temperature' ) ;
55
+ }
56
+ setMinTemp ( temp ) ;
57
+ } ;
58
+
59
+ const verifyAndSetMaxTemp = ( temp : string ) => {
60
+ if ( Number ( temp ) <= Number ( minTemp ) ) {
61
+ Alert . alert ( 'Max temperature must be greater than min temperature' ) ;
62
+ }
63
+ setMaxTemp ( temp ) ;
64
+ } ;
65
+
66
+ async function readNdef ( ) {
67
+ try {
68
+ // register for the NFC tag with NDEF in it
69
+ await NfcManager . requestTechnology ( NfcTech . Ndef ) ;
70
+
71
+ // Extract NDEF message (if present)
72
+ const tag = await NfcManager . getTag ( ) ;
73
+
74
+ // Extract NDEF message (if present)
75
+ if ( tag ?. ndefMessage ) {
76
+ const rawValue = tag . ndefMessage . map ( record =>
77
+ String . fromCharCode ( ...record . payload )
78
+ ) ;
79
+
80
+ let jsonValue = JSON . parse ( rawValue . toString ( ) ) ;
81
+ var nfcColor = colors . find ( c => c . hex . toLowerCase ( ) === jsonValue . color_hex . toLowerCase ( ) ) ;
82
+ var nfcType = types . find ( t => t . value . toLowerCase ( ) === jsonValue . type . toLowerCase ( ) ) ;
83
+
84
+ setColor ( nfcColor ?. value ?? 'blue' ) ;
85
+ setType ( nfcType ?. value ?? 'pla' ) ;
86
+ setMinTemp ( jsonValue . min_temp . toString ( ) ) ;
87
+ setMaxTemp ( jsonValue . max_temp . toString ( ) ) ;
88
+ } else {
89
+ Alert . alert ( 'No NDEF message found on the tag.' ) ;
90
+ }
91
+ } catch ( ex ) {
92
+ console . warn ( 'Oops!' , ex ) ;
93
+ } finally {
94
+ // stop the nfc scanning
95
+ NfcManager . cancelTechnologyRequest ( ) ;
96
+ }
97
+ }
98
+
99
+ const writeNdef = async ( ) => {
100
+
101
+ if ( Number ( minTemp ) >= Number ( maxTemp ) ) {
102
+ Alert . alert ( 'Min temperature must be less than max temperature' ) ;
103
+ return ;
104
+ }
105
+
106
+ try {
107
+ await NfcManager . requestTechnology ( NfcTech . Ndef ) ;
108
+
109
+ const jsonData = {
110
+ version : '1.0' ,
111
+ protocol : 'openspool' ,
112
+ color_hex : colors . find ( c => c . value === color ) ?. hex ,
113
+ type : type ,
114
+ min_temp : Number ( minTemp ) ,
115
+ max_temp : Number ( maxTemp ) ,
116
+ brand : 'Generic' ,
117
+ } ;
118
+ const jsonStr = JSON . stringify ( jsonData ) ;
119
+ const ndefRecords = Ndef . record ( Ndef . TNF_MIME_MEDIA , 'application/json' , '1' , jsonStr ) ;
120
+
121
+ //requires an array, but makes it a single once it's passed in
122
+ const bytes = await Ndef . encodeMessage ( [ ndefRecords ] ) ;
123
+
124
+ if ( bytes ) {
125
+ await NfcManager . ndefHandler
126
+ . writeNdefMessage ( bytes ) ;
127
+ }
128
+ } catch ( error ) {
129
+ console . error ( 'Error writing JSON:' , error ) ;
130
+ } finally {
131
+ NfcManager . cancelTechnologyRequest ( ) ;
132
+ }
133
+ } ;
134
+
58
135
59
136
return (
60
137
< SafeAreaView style = { styles . container } >
@@ -63,7 +140,7 @@ const OpenSpool = () => {
63
140
64
141
< View style = { styles . circleContainer } >
65
142
< View style = { [ styles . circle , {
66
- backgroundColor : colors . find ( c => c . value === color ) ?. hex || color
143
+ backgroundColor : `# ${ colors . find ( c => c . value === color ) ?. hex } ` || color ,
67
144
} ] } />
68
145
</ View >
69
146
@@ -80,8 +157,8 @@ const OpenSpool = () => {
80
157
value = { color }
81
158
onChange = { item => setColor ( item . value ) }
82
159
renderItem = { renderColorItem }
83
- placeholderStyle = { { color : '#999' } }
84
- selectedTextStyle = { { color : '#ffffff' } }
160
+ placeholderStyle = { styles . placeHolder }
161
+ selectedTextStyle = { styles . selected }
85
162
/>
86
163
</ View >
87
164
@@ -96,8 +173,8 @@ const OpenSpool = () => {
96
173
placeholder = "Select type"
97
174
value = { type }
98
175
onChange = { item => setType ( item . value ) }
99
- placeholderStyle = { { color : '#999' } }
100
- selectedTextStyle = { { color : '#ffffff' } }
176
+ placeholderStyle = { styles . placeHolder }
177
+ selectedTextStyle = { styles . selected }
101
178
/>
102
179
</ View >
103
180
@@ -112,9 +189,9 @@ const OpenSpool = () => {
112
189
valueField = "value"
113
190
placeholder = "Min temp"
114
191
value = { minTemp }
115
- onChange = { item => setMinTemp ( item . value ) }
116
- placeholderStyle = { { color : '#999' } }
117
- selectedTextStyle = { { color : '#ffffff' } }
192
+ onChange = { item => verifyAndSetMinTemp ( item . value ) }
193
+ placeholderStyle = { styles . placeHolder }
194
+ selectedTextStyle = { styles . selected }
118
195
/>
119
196
</ View >
120
197
@@ -128,9 +205,9 @@ const OpenSpool = () => {
128
205
valueField = "value"
129
206
placeholder = "Max temp"
130
207
value = { maxTemp }
131
- onChange = { item => setMaxTemp ( item . value ) }
132
- placeholderStyle = { { color : '#999' } }
133
- selectedTextStyle = { { color : '#ffffff' } }
208
+ onChange = { item => verifyAndSetMaxTemp ( item . value ) }
209
+ placeholderStyle = { styles . placeHolder }
210
+ selectedTextStyle = { styles . selected }
134
211
/>
135
212
</ View >
136
213
</ View >
@@ -139,13 +216,13 @@ const OpenSpool = () => {
139
216
< View style = { styles . buttonContainer } >
140
217
< TouchableOpacity
141
218
style = { styles . button }
142
- onPress = { handleReadTag }
219
+ onPress = { readNdef }
143
220
>
144
221
< Text style = { styles . buttonText } > Read Tag</ Text >
145
222
</ TouchableOpacity >
146
223
< TouchableOpacity
147
224
style = { styles . button }
148
- onPress = { handleWriteTag }
225
+ onPress = { writeNdef }
149
226
>
150
227
< Text style = { styles . buttonText } > Write Tag</ Text >
151
228
</ TouchableOpacity >
@@ -200,9 +277,9 @@ const styles = StyleSheet.create({
200
277
color : '#999' , // Lighter grey for navigation icons
201
278
} ,
202
279
circle : {
203
- width : 140 ,
204
- height : 140 ,
205
- borderRadius : 70 , // Exactly half of width/height
280
+ width : 180 ,
281
+ height : 180 ,
282
+ borderRadius : 90 , // Exactly half of width/height
206
283
alignContent : 'center' ,
207
284
backgroundColor : 'black' ,
208
285
overflow : 'hidden' , // This helps with some rendering artifacts[5]
@@ -278,7 +355,6 @@ const styles = StyleSheet.create({
278
355
} ,
279
356
colorLabel : {
280
357
fontSize : 16 ,
281
- color : '#ffffff' , // White text for color labels
282
358
283
359
} ,
284
360
colorSwatch : {
@@ -289,6 +365,12 @@ const styles = StyleSheet.create({
289
365
borderWidth : 1 ,
290
366
borderColor : 'transparent' ,
291
367
} ,
368
+ placeHolder : {
369
+ color : '#999' ,
370
+ } ,
371
+ selected : {
372
+ color : '#ffffff' ,
373
+ } ,
292
374
} ) ;
293
375
294
376
export default OpenSpool ;
0 commit comments