๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๊ฐœ๋ฐœ์ด์•ผ๊ธฐ

DSC KR Solution Challenge hackathon

 
 
 

ํ•ด์ปคํ†ค์ด ๋๋‚œ ํ›„์— ์Šฌ๋ž™์˜ ์Šค๋ ˆ๋“œ์™€ ์ปค๋ฐ‹ ๋ฉ”์„ธ์ง€, ๊นƒํ—™์˜ ์—ฌ๋Ÿฌ ๊ธฐ๋ก์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํšŒ๊ณ ํ•ด๋ณด๋ ค ํ•œ๋‹ค.

flutter ์— firebase ๋ฅผ ์—ฐ๋™ํ•˜์—ฌ ์ง„ํ–‰ํ–ˆ๋‹ค.

๋‚˜๋Š” ์„œ๋ฒ„๋ฅผ ์œ„์ฃผ๋กœ ๊ฐœ๋ฐœํ–ˆ๋‹ค.

github.com/qwa310/DSC-Hackathon


ํ•ด์ปคํ†ค ์ •๋ณด

๋‚˜๋Š” DSC member ์ž๊ฒฉ์œผ๋กœ ์ด ํ•ด์ปคํ†ค์— ์ฐธ์—ฌํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ฒฐ๊ณผ๋ฌผ

๋‹จ ์ผ์ฃผ์ผ๋งŒ์— 2๋ช…์ด ๊ฐœ๋ฐœ์— ์ฐธ์—ฌํ•œ ์–ดํ”Œ์˜ ์‹œ์—ฐ ์˜์ƒ์ด๋‹ค.

๋ญ”๊ฐ€ ์ด์ƒํ•œ ๊ด‘๊ณ  ๋ฉ˜ํŠธ๊ฐ™์ง€๋งŒ ์•ฑ ๊ฐœ๋ฐœ์€ ๋งน์„ธ์ฝ” ๋‚œ์ƒ ์ฒ˜์Œ์ด๊ณ  ์‚ฌ์‹ค ์ƒ ์ฒซ ๊ฐœ๋ฐœ ๊ฒฝํ—˜๊ณผ ๋‹ค๋ฅด์ง€ ์•Š์•˜๋˜ ํ”„๋กœ์ ํŠธ

โœจ 01.30: ์ฃผ์ œ ์„ ์ •

์ „์ฒด OT๊ฐ€ ๋๋‚˜๊ณ  ํŒ€ ๋งค์นญ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐœํ‘œ๋˜์—ˆ๋‹ค.

์„œ๋กœ ๋‹ค ๋‹ค๋ฅธ ํ•™๊ต์˜ ์‚ฌ๋žŒ๋“ค๊ณผ ์˜จ๋ผ์ธ(์Šฌ๋ž™)์œผ๋กœ ์†Œํ†ตํ•˜๋ฉฐ ์ง„ํ–‰ํ–ˆ๋‹ค.

4๋ช…์ด ํ•œ ํŒ€์ด ๋˜์—ˆ๋Š”๋ฐ ๊ฐ ์‚ฌ๋žŒ ๋‹น 2๊ฐœ์˜ ์•„์ด๋””์–ด๋ฅผ ์ œ์•ˆํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

SC Solution Challenge์—์„œ ๊ณต์‹ ์ง€์ •ํ•œ ์ฃผ์ œ์ธ UN ์ง€์†๊ฐ€๋Šฅ๋ฐœ์ „๋ชฉํ‘œ UN-SDGs (UN Sustainable Development Goals) 17๊ฐ€์ง€ ์ค‘ ํ•œ ๊ฐ€์ง€์— ๋ถ€ํ•ฉ๋˜๋ฉด ๋˜๋Š”๋ฐ ์‚ฌ์‹ค์ƒ ์ž์œ  ์ฃผ์ œ๋‚˜ ๋งˆ์ฐฌ๊ฐ€์ง€์ฒ˜๋Ÿผ ๋Š๊ปด์กŒ๋‹ค. DSC ewha ๋ฉค๋ฒ„๋ถ„๋“ค๊ณผ ์˜คํ”„๋ผ์ธ ํšŒ์˜๋ฅผ ํ•˜๊ณ  ์ง€ํ•˜์ฒ  ํƒ€๊ณ  ์ง‘ ์˜ค๋Š” ๊ธธ์— 2์‹œ๊ฐ„ ๋™์•ˆ ๋จธ๋ฆฌ์— ์ฅ๋‚ ์ •๋„๋กœ ์—ด์‹ฌํžˆ ์ƒ๊ฐํ–ˆ๋‹ค.ํ‰์†Œ์— ๋งŽ์€ ์ƒ๊ฐ์„ ์•ˆํ•˜๊ณ  ์‚ด์•„์„œ ์—†๋Š” ์•„์ด๋””์–ด๋ฅผ ๋š๋”ฑ ๋‚ด ๋†“์œผ๋ผ๊ณ  ํ•˜๋‹ˆ ๋„ˆ๋ฌด ์–ด๋ ค์› ๋‹ค.

ํ•ด์ปคํ†ค ๊ธฐ๊ฐ„ ์ค‘์— ์ œ์ผ ์ •์‹ ์ ์œผ๋กœ ์ŠคํŠธ๋ ˆ์Šค๋ฅผ ๋งŽ์ด ๋ฐ›์€ ๋‚ ์ด์—ˆ๋‹ค. ์•„์ด๋””์–ด ๋…ธํŠธ๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•ด์„œ ์ถ•์ ํ•ด๋†“์„ ํ•„์š”๋ฅผ ๋Š๊ผˆ๋‹ค. ๋‚˜๋Š” 11๋ฒˆ๊ณผ 13๋ฒˆ์— ๊ด€๋ จ๋œ ์ฃผ์ œ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์—ˆ๊ณ  ํˆฌํ‘œ๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ์•„์ด๋””์–ด๊ฐ€ ์ฑ„ํƒ๋˜์—ˆ๋‹ค. (๊ทผ๋ฐ ๋‚ด ์•„์ด๋””์–ด๋„ ๊ตฌํ˜„ํ• ๋งŒ ํ•˜๋‹ค. ์–ธ์  ๊ฐ€ ๋˜์ง€ ์•Š์„๊นŒ?)

 

๊ฒฐ๋ก ์ ์œผ๋กœ, ๋ณธ์ธ์ด ์†Œ๋น„ํ•˜๋Š” ์ „๊ธฐ๋Ÿ‰์„ ์ธ์ง€ํ•˜๊ณ  ์Šค์Šค๋กœ ์ ๊ฒ€ํ•˜๋ฉด์„œ ์ผ์ƒ ์†์—์„œ ๋ฌธ์ œ๋ฅผ ๊ฐœ์„ ํ•ด ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ๋„์šธ ์ˆ˜ ์žˆ๋Š” ์–ดํ”Œ์„ ์ฃผ์ œ๋กœ ์ •ํ–ˆ๋‹ค.

โœจ 01.31: idea ํšŒ์˜, ๊ฐœ๋ฐœ ์Šคํƒ ์„ ์ •

idea ํšŒ์˜

๋‹ค์Œ ๋‚  ์ด์–ด์„œ ์•„์ด๋””์–ด๋ฅผ ๊ตฌ์ฒดํ™”ํ–ˆ๋‹ค. ์ •๋ฏผ๋‹˜์˜ ์ง€ํœ˜๋กœ ์•„์ด๋””์–ด๋Š” ์ˆœ์กฐ๋กญ๊ฒŒ ๊ตฌ์ฒดํ™”๋˜์—ˆ๋‹ค.

์šฐ๋ฆฌ ์–ดํ”Œ์˜ ์ด๋ฆ„์œผ๋กœ Saver ๊ฐ€ ์ฑ„ํƒ๋˜์—ˆ๊ณ  ์šฐ๋ฆฌ ํŒ€ ์ด๋ฆ„์€ Power Rangers ๊ฐ€ ๋˜์—ˆ๋‹ค.

๊ฐœ๋ฐœ ์Šคํƒ ์„ ์ •

์ดํ›„ ๊ฐœ๋ฐœ ์Šคํƒ์— ๋Œ€ํ•ด ์‚ฌ์ „ ์กฐ์‚ฌ๋ฅผ ํ–ˆ๋Š”๋ฐ ์œ„์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”๋‹ค.

์‚ฌ์‹ค์ƒ ๋‚ด๊ฐ€ (์ฃผํ™ฉ์ƒ‰) ์ œ์ผ ๋ฌธ์ œ์˜€๋‹ค.

ํ•œ ๋ถ„์€ flutter๋กœ ์•ฑ ๊ฐœ๋ฐœ์„ ํ•ด๋ณด์…จ๊ณ 

ํ•œ ๋ถ„์€ ๊ฐœ๋ฐœ์ž๋กœ ์ง€์›ํ•˜์…จ์ง€๋งŒ ์•„์ง ๊ฐœ๋ฐœ์„ ํ•œ ๋ฒˆ๋„ ํ•ด๋ณด์ง€ ๋ชปํ–ˆ๊ณ  flutter๋„ ์‚ฌ์‹ค์ƒ ์ž˜ ๋ชจ๋ฅธ๋‹ค๊ณ  ํ•˜์…จ๋‹ค.

๋‚˜ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š”, ์ง€์›์„œ์— ๊ฐ€๋Šฅํ•œ ์Šคํƒ์œผ๋กœ ๋‹น๋‹นํ•˜๊ฒŒ firebase ํ•˜๋‚˜ ์ผ๋˜์ง€๋ผ ๋‚ด๊ฐ€ ๋‹น์—ฐํ•˜๊ฒŒ ๋งž์ถฐ๋“œ๋ฆฌ๋Š” ๊ฒŒ ๋งž์•˜๋‹ค.

์•„์ด๋””์–ด๋Š” ์•ฑ์„ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ์œผ๋กœ ํ˜๋Ÿฌ๊ฐ”๊ณ  ์•ฑ ๊ฐœ๋ฐœ์„ ์ „ํ˜€ ์ ‘ํ•ด๋ณธ ์ ์ด ์—†์—ˆ๋˜ ๋‚˜๋Š” ์‹ฌ๊ฐ์„ฑ์„ ๋Š๊ผˆ๋‹ค.

 

์ผ๋‹จ ์•ฑ ๊ฐœ๋ฐœ์„ ํ•˜๋Š” ์ฃผ๋ณ€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ SOS๋ฅผ ์ฒญํ–ˆ๋‹ค.

๋•๋ถ„์— ์•„์ฃผ ๋น ๋ฅด๊ฒŒ ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค ์‚ฌ์šฉ๋ฒ•์„ ์–ด๋ ดํ’‹์ด ๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๋ถˆํ–‰ ์ค‘ ๋‹คํ–‰์ธ ๊ฒƒ์€ ๊ธฐ์กด์— ์Šคํ”„๋ง/์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ intelliJ๋กœ ๊ฐœ๋ฐœํ–ˆ๋Š”๋ฐ Android Studio ํˆด์ด inteiiJ ๊ธฐ๋ฐ˜ ์•ฑ ๊ฐœ๋ฐœ ํˆด์ด๋ผ์„œ ์–ด๋ ต์ง€ ์•Š๊ฒŒ ์ž…๋ฌธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

๊ฐœ๋ฐœ ๊ฒฝํ—˜์ด ๋„ˆ๋ฌด ์—†์–ด์„œ ๋ถˆ๊ฐ€๋Šฅ์— ๋„์ „ํ•˜๋Š” ๊ธฐ๋ถ„์ด์—ˆ๋‹ค.

๊ฐœ๋ฐœ ์Šคํƒ์€ flutter + firebase๋กœ ์ •ํ•˜๊ฒŒ ๋˜์—ˆ๊ณ  ๋‚˜๋Š” ๋„ˆ๋ฌด๋„ˆ๋ฌด ๋ถˆ์•ˆํ•œ ๋งˆ์Œ์œผ๋กœ ์ž ์— ๋“ค์—ˆ๋‹ค.

โœจ 02.01: ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๊ตฌ์ถ•

์„ค์น˜๋ถ€ํ„ฐ...

์ผ์–ด๋‚˜์„œ ์ผ๋‹จ android studio, flutter ์„ค์น˜๋ถ€ํ„ฐ ํ–ˆ๋‹ค. ์–ด์ œ ์ •๋ฏผ๋‹˜๊ป˜ repo ์ƒ์„ฑ๊ณผ ํ”„๋กœ์ ํŠธ initial์„ ๋ถ€ํƒ๋“œ๋ ธ๋Š”๋ฐ ํ•ด์ฃผ์…”์„œ clone ํ›„ ์‹คํ–‰ํ•ด๋ณด์•˜๋‹ค. ๋‹น์—ฐํ•˜์ง€๋งŒ ์‹คํ–‰์ด ์•ˆ๋๋‹ค. 2์‹œ๊ฐ„ ๋™์•ˆ ๊ฒ€์ƒ‰ํ•ด๋ณด๋ฉด์„œ ์ผ๋‹จ ์‹คํ–‰์€ ๋˜๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ๊ธฐํš ํšŒ์˜

์ดํ›„ ์˜คํ›„ 1์‹œ์— ๊ฐ™์ด ํšŒ์˜ํ•˜๋ฉด์„œ ์•„์ด๋””์–ด๋ฅผ ๋”์šฑ ๊ตฌ์ฒดํ™”ํ–ˆ๋‹ค. ์šฐ๋ คํ–ˆ๋˜ ๊ฒƒ์— ๋น„ํ•ด ํšŒ์˜๋Š” ์ •๋ง์ •๋ง ๋นจ๋ฆฌ ๋๋‚ฌ๋‹ค.

์ฑ… ๋นŒ๋ฆฌ๋Ÿฌ ๋„์„œ๊ด€ !

์ •๋ง๋กœ ์ด์   ๊ตฌํ˜„์ด ๋ฌธ์ œ์˜€๋‹ค. ํšŒ์˜๊ฐ€ ๋๋‚˜๊ณ  ๋ฐ”๋กœ ์ปดํ“จํ„ฐ ์•ž์—์„œ ์ผ์–ด๋‚˜์„œ ๋„์„œ๊ด€์„ ํ–ฅํ–ˆ๊ณ  ์ •์งํ•˜๊ฒŒ flutter, ํŒŒ์ด์–ด๋ฒ ์ด์Šค ํ‚ค์›Œ๋“œ๋กœ ๊ฒ€์ƒ‰๋˜๋Š” ๋‘ ์ฑ…์„ ์ง‘์–ด์™”๋‹ค.

์ง‘์— ์™€์„œ ์ผ๋‹จ ์ฑ…์„ ํŽผ์ณ๋“ค์—ˆ๋‹ค.

flutter๋Š” dart๋ž€ ์–ธ์–ด๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๋Š”๋ฐ ๋‚œ์ƒ ์ฒ˜์Œ ๋“ฃ๋Š” ์–ธ์–ด๋ผ์„œ ์ผ๋‹จ ๋ฌธ๋ฒ•๋ถ€ํ„ฐ ๋ดค๋‹ค. ๊ฐ์ฒด์ง€ํ–ฅ(java) + js ๋ฌธ๋ฒ•์ด ๋ง‰ ์„ž์—ฌ์„œ ์ •์‹ ์ด ์—†์—ˆ๋‹ค. ๋ณ„ ๋ฉ‹์ง„ ๊ธฐ๋Šฅ์€ ๋‹ค ์ง€์›ํ•˜๋Š”๋ฐ ๋‚ด๊ฐ€ ํก์ˆ˜๋ฅผ ํ•˜๋‚˜๋„ ๋ชปํ•˜๋Š” ๊ธฐ๋ถ„์ด์—ˆ๋‹ค. ๋˜ํ•œ  js ๋Š” ๋ฐ”๋‹๋ผ ์ˆ˜์ค€ ์ •๋„๋กœ ์•Œ๊ณ  ์žˆ๋‹ค๊ฐ€ es ๋ฌธ๋ฒ•์„ ์•Œ ํ•„์š”์„ฑ์„ ๋Š๊ปด ์กฐ๊ธˆ์”ฉ ์ตํžˆ๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ์ฝœ๋ฐฑ ๊ฐœ๋…์„ ์ •ํ™•ํžˆ ๋ชจ๋ฅด๋Š” ๋‚˜์—๊ฒ ์ฅ์•ฝ์ด ๋”ฐ๋กœ ์—†์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์–ธ์–ด๊ฐ€ indentation์€ ๋˜ ์™œ์ด๋ž˜? ๊ธฐ๋ณธ 4์นธ ์ •๋„๋Š” ์‹œ์›์‹œ์›ํ•˜๊ฒŒ ํƒญ ๋˜์–ด์•ผํ•˜๋Š” ๊ฑด ์•„๋‹ˆ๋ƒ๊ณ . ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค๋Š” ์—˜๋ฆฌ๋จผํŠธ๋กœ ์ ‘๊ทผํ•˜๋˜๋ฐ dart๋Š” ์ฝ”๋”ฉ์„ ๋‚˜์—ดํ•˜๋Š” ์‹์œผ๋กœ ํ•˜๊ณ  ๋ฌด์Šจ 2์นธ์”ฉ ๋“ค์—ฌ์“ฐ๊ธฐํ•˜๋Š” ํ˜•์‹์ด๋ผ ์ฝ”๋“œ๊ฐ€ ๋ˆˆ์— ๋“ค์–ด์˜ค์ง€ ์•Š์•˜๋‹ค. ์ดˆ๋ฐ˜์—๋Š” ๋„ˆ๋ฌด ๋‹ต๋‹ตํ•˜๋‹ค๊ณ  ๋Š๊ผˆ๋‹ค.

PR #1 firebase ์—ฐ๋™

anyway, ์ด ์ฑ…์„ ํ†ตํ•ด ์ผ๋‹จ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋ถ€ํ„ฐ ์ตํ˜”๊ณ  Dart ์–ธ์–ด, ๊ฐ„๋‹จํ•œ ์‹ค์Šต์œผ๋กœ ์งง์€ ์‹œ๊ฐ„์— ๊ณต๋ถ€ํ–ˆ๋‹ค.

์ดํ›„ firebase ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ƒ์„ฑ๋œ firebase ํ”„๋กœ์ ํŠธ์™€ flutter ํ”„๋กœ์ ํŠธ ์—ฐ๋™ํ–ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  bigdata.kepco.co.kr/cmsmain.do?scode=S01&pcode=000171&redirect=Y ์ด ํŽ˜์ด์ง€์˜ ๋ฐ์ดํ„ฐ ๊ฐ€๊ณตํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด db์— ์ €์žฅํ–ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฃจ๊ฐ€ ๋๋‚ฌ๋‹ค.

โœจ 02.02: ํšŒ์›๊ฐ€์ž…/๋กœ๊ทธ์ธ

PR #3 ํšŒ์›๊ฐ€์ž… ๊ธฐ๋Šฅ ๊ตฌํ˜„

ํšŒ์›๊ฐ€์ž…์„ ํ•˜๋ฉด ํšŒ์›์ด ์ƒ์„ฑ๋˜๊ณ  db์— ํšŒ์› ์ •๋ณด๊ฐ€ ์ €์žฅ๋˜๋Š” ์ฝ”๋“œ๋ฅผ pr ํ–ˆ๋‹ค.

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MainPage());
}

firebase๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฉ”์ธ์—์„œ initial ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์“ฐ๊ณ 

  void _createUser(User user) {
    auth.createUserWithEmailAndPassword(email: user.email, password: user.password)
        .then((cred) => {
          firestore
            .collection('user')
            .doc(cred.user.uid)
            .set({
              'uid': cred.user.uid,
              'name': user.name,
              'email': user.email,
              'region': user.region
            })

user ํด๋ž˜์Šค์— ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’์„ ๋‹ด์•„ db์— ์ด๋ฆ„, ์ด๋ฉ”์ผ, ์ง€์—ญ ์ •๋ณด๋ฅผ ์ €์žฅํ–ˆ๋‹ค.

ํšŒ์› ๊ฐ€์ž… ์‹œ ์ƒ์„ฑ๋œ ๊ณ„์ • ๊ณ ์œ ์˜ uid๋ฅผ db ๋ฌธ์„œ์— ์ €์žฅํ•ด ์ดํ›„ ๋กœ๊ทธ์ธ๋œ user๋ฅผ ๋”์šฑ ์ฐพ๊ธฐ ์‰ฝ๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.

PR #6 ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„, ํšŒ์›๊ฐ€์ž…/๋กœ๊ทธ์ธ ์ค‘ error catch

๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ๋„ firebase authentication ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์—ฌ ์‰ฝ๊ฒŒ ์ฝ”๋”ฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์—๋Ÿฌ๋ฅผ ์บ์น˜ํ•˜๋Š” ๊ณผ์ •์—์„œ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ ธ๋‹ค.

error catch ์ฝ”๋“œ๋ฅผ ๋ถ„๋ช… ์ผ๋Š”๋ฐ ์บ์น˜๋ฅผ ๋ชปํ–ˆ๋‹ค.

stackoverflow.com/questions/54687944/how-to-catch-exception-of-asynchronous-function-in-flutter

์ด ๊ธ€์„ ํ†ตํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ, ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์‹คํ–‰๋œ ํ›„ ์—๋Ÿฌ๋ฅผ ํ™•์ธํ•ด์•ผํ•˜๋Š”๋ฐ ์ฆ‰ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์˜ ์˜ˆ์™ธ๋ฅผ ์ฒดํฌํ•ด์•ผํ•˜๋Š”๋ฐ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ณ  ์ฝ”๋“œ๋ฅผ ์งฐ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

catch (e) {
      if (e.code == 'email-already-in-use') {
        print('The account already exists for that email.');
      } else if (e.code == 'invalid-email') {
        print('The email address is badly formatted.');
      } else if (e.code == 'weak-password') {
        print('The password provided is too weak.');
      } else {
        print(e);
      }
    }

๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ๋„

  • id์ธ email์„ ๋“ฑ๋ก๋œ ํšŒ์› ์ •๋ณด์—์„œ ์ฐพ์„ ์ˆ˜ ์—†์„ ๋•Œ๋Š” e.code == user-not-found ์ฝ”๋“œ๋กœ,
  • ํŒจ์Šค์›Œ๋“œ๊ฐ€ ํ‹€๋ ธ์„ ๋•Œ๋Š” e.code == wrong-password ์ฝ”๋“œ๋กœ

์—๋Ÿฌ๋ฅผ ํ•ธ๋“ค๋งํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ๋„˜๊ฒจ๋“œ๋ ธ๊ณ  ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ์ดํ›„ ํŒ์—… ์ฐฝ์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ์ฐฝ์„ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์„ ์ •๋ฏผ๋‹˜๊ป˜์„œ ๋ฐ”๋กœ ๊ตฌํ˜„ํ•ด์ฃผ์…จ๋‹ค. (PR #7)

 

์‹ค์‹œ๊ฐ„ ํšŒ์˜

๊ฐ์ž ๊ฐ€์ง€๊ณ  ์žˆ๋Š” issue ์— ๋Œ€ํ•ด์„œ ์ด์•ผ๊ธฐ๋ฅผ ํ–ˆ๋‹ค. ๋””์ž์ด๋„ˆ ๋ถ„๊ป˜์„œ๋Š” ์œ„์™€ ๊ฐ™์ด 1์ฐจ ์™€์ด์–ด ํ”„๋ ˆ์ž„ ์™„์„ฑ ๋ณธ์„ ๊ฑด๋„ค์ฃผ์…จ๋‹ค. ์ „๋‚  ํšŒ์˜๋ฅผ ํ†ตํ•ด ์ด์•ผ๊ธฐํ–ˆ๋˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ ํ™”๋ฉด์˜ ๋ผˆ๋Œ€๋ฅผ ๊ทธ๋ ค์˜ค์…จ๋‹ค. ์„ค๋ช…์„ ๋“ค์œผ๋ฉด์„œ ๋ฌด์—‡์„ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผ ํ• ์ง€ ๋” ํ™•์‹คํžˆ ์™€๋‹ฟ์•˜๋‹ค. ๋””์ž์ด๋„ˆ๊ฐ€ ์žˆ๋Š” ๊ฐœ๋ฐœ๊ณผ ์—†๋Š” ๊ฐœ๋ฐœ์˜ ์ฐจ์ด์ ์— ๋Œ€ํ•ด์„œ ๋งŽ์ด ๋Š๋‚€ ํšŒ์˜์˜€๋‹ค.

โœจ 02.03: Create, welcome ํŽ˜์ด์ง€

PR #8 Create data

ํ”„๋ก ํŠธ ์ •๋ฏผ๋‹˜์ด ๊ตฌํ˜„ํ•ด๋‘์‹  ์ „์ž๊ธฐ๊ธฐ ์ข…๋ฅ˜์™€ ์‚ฌ์šฉ์‹œ๊ฐ„ ์ •๋ณด ์ž…๋ ฅ ํŽ˜์ด์ง€์—์„œ submit ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด

์•„๋ž˜์™€ ๊ฐ™์ด ๋กœ๊ทธ์ธ ๋œ ํ•ด๋‹น ์œ ์ €์˜ ๊ณ ์œ  id์— ์ •๋ณด๊ฐ€ ์ €์žฅ๋˜๋„๋ก ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด db ๊ตฌ์กฐ๋Š” ๋‹ค ๋ฐ”๋€๋‹ค. firebase๊ฐ€ ์ง€์›ํ•˜๋Š” db์—๋Š” firestore์™€ realtime database ๋‘ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋Š”๋ฐ ๋‘˜ ๋‹ค NoSQL ์ด๋‹ค. ๊ทผ๋ฐ ๋‚˜๋Š” ์ด ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๋ฅผ ์ „ํ˜€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์ƒํƒœ์—์„œ ์ผ๋‹จ '์ •๋ณด๋ฅผ ์ €์žฅํ•ด๋ณด์ž'๋Š” ๊ด€์ ์—๋งŒ ์ฃผ๋ชฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— 1์ฐจ์ ์ธ ๋ชฉํ‘œ๋Š” ๋‹ฌ์„ฑํ•ด๋‘์–ด์„œ ๋ฉˆ์ถ”์—ˆ๋‹ค.

PR #9 welcome page

์ดํ›„ ๊ตฌํ˜„๋œ ํ”„๋ก ํŠธ ํŽ˜์ด์ง€๊ฐ€ ์—†์–ด์„œ ์–ด๋–ค ์ž‘์—…์„ ๊ณ„์†ํ•ด์•ผํ• ์ง€ ์กฐ๊ธˆ ๋ฐฉํ™ฉํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค๊ฐ€ ๋‚˜๋„ ๊ทธ๋Ÿผ ํ”„๋ก ํŠธ๋ฅผ ์ž‘์—…ํ•ด๋ด์•ผ ๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ณค ์‹คํ–‰์— ์˜ฎ๊ฒผ๋‹ค. ๋ณดํ†ต ์•ฑ์„ ์‹คํ–‰ํ•˜๋ฉด ์•ฑ์ด ๋กœ๋”ฉ๋  ๋•Œ ๋ณด์—ฌ์ง€๋Š” ์‹œ์ž‘ ํŽ˜์ด์ง€๊ฐ€ ์žˆ๋Š”๋ฐ ์ œ์ผ ์‰ฌ์›Œ๋ณด์—ฌ์„œ ์ด ํŽ˜์ด์ง€๋ฅผ ๊ฑด๋“ค์˜€๋‹ค. ์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒŒ ๋งž๋‚˜ ์‹ถ์—ˆ์ง€๋งŒ ์ž„์˜๋กœ ์ง€์ •ํ•œ 4์ดˆ๊ฐ€ ์ง€๋‚˜๋ฉด ๊ณ„์ • ์ •๋ณด์˜ ์œ ๋ฌด๋ฅผ ํŒ๋‹จํ•˜์—ฌ ๋กœ๊ทธ์ธ์ด ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€๊ณ , ๊ณ„์ • ์ •๋ณด๊ฐ€ ์žˆ๋‹ค๋ฉด ๋งˆ์ดํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.

์‹ค์‹œ๊ฐ„ ํšŒ์˜

 

โœจ 02.04: Read

PR #12 GET mypage data

๊ทธ๋™์•ˆ CRUD ์ค‘ create ์— ํ•ด๋‹นํ•˜๋Š” ์ž‘์—…๋งŒ ํ•ด์™”๊ณ  read ๊ด€๋ จ ์ž‘์—…์„ ์ฒ˜์Œ ์‹œ๋„ํ•ด๋ณด๋Š” ๋‚ ์ด์—ˆ๋‹ค. ํ”„๋ก ํŠธ ์ •๋ฏผ ๋‹˜์ด ๋งˆ์ดํŽ˜์ด์ง€๋ฅผ ๊ตฌํ˜„ํ•˜์…”์„œ ์ด ํŽ˜์ด์ง€์— ๋กœ๊ทธ์ธ๋œ ์œ ์ €์˜ ์ •๋ณด๋ฅผ ํ˜ธ์ถœํ•ด ๋ณด์—ฌ์ฃผ๋Š” ์ž‘์—…์„ ํ–ˆ๋‹ค. ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ read ์ž‘์—…์ด๊ธฐ๋„ ํ–ˆ๋‹ค. 

firestore์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋Š”๋ฐ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ๋„ ์ „์— ๋งˆ์ดํŽ˜์ด์ง€๊ฐ€ ๊ทธ๋ ค์กŒ๋‹ค๊ฐ€ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ ๋’ค ๋‹ค์‹œ ๋งˆ์ดํŽ˜์ด์ง€๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. request/response ๊ฐœ๋…์„ ์ž˜ ๋ชฐ๋ผ์„œ ๋‚˜ํƒ€๋‚˜๋Š” ์˜ค๋ฅ˜์ด์—ˆ๋‹ค.

      body: StreamBuilder(
        stream: currentStream,
        builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
          if (!snapshot.hasData) {
            return CircularProgressIndicator();
          } return MyPageView(snapshot.data);
        },

๋‚˜๋Š” ์œ„์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด StreamBuilder๋ฅผ ํ™œ์šฉํ–ˆ๋‹ค. (์ด์— ๋Œ€ํ•ด ์•Œ ์ˆ˜ ์žˆ๋Š” 1๋ถ„ ๋™์˜์ƒ์ธ๋ฐ ์ •๋ง ๋„์›€์ด ๋งŽ์ด ๋˜์—ˆ๋‹ค. # ) ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋กœ์ง์„ ์„ค๋ช…ํ•˜์ž๋ฉด, ์ž๋™์œผ๋กœ ์‹คํ–‰๋˜๋Š” init ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋จผ์ € ๋ถˆ๋Ÿฌ์˜จ๋‹ค. ์•„์ง ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ๋กœ๋”ฉ ํŽ˜์ด์ง€ ( CircluarProgressIndicator() - ๋น™๊ธ€๋น™๊ธ€ ๋„๋Š” ํŽ˜์ด์ง€)๋ฅผ ๋ณด์—ฌ์ฃผ๋‹ค๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ž˜ ๊ฐ€์ ธ์˜ค๋ฉด ๋งˆ์ดํŽ˜์ด์ง€๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ธด๋‹ค. ์ดํ›„ MyPageView ์—์„œ ๋ฐ์ดํ„ฐ๊ฐ’์— ์ ‘๊ทผํ•˜์—ฌ ๋ Œ๋”๋ง๋œ ํŽ˜์ด์ง€๊ฐ€ ๋ณด์ด๊ฒŒ ๋œ๋‹ค.

์ด ๊ณผ์ •์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์™€ ๊ฐ€๊ณตํ•˜๋Š” ๋ถ€๋ถ„๊ณผ view ํŽ˜์ด์ง€๋ฅผ ๋‚˜๋ˆ„์—ˆ๋‹ค. ํ•œ ํŒŒ์ผ ๋‚ด์—์„œ ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๋Š” ๊ฑด ์‹œ๊ฐ„ ๋ฌธ์ œ์˜€๊ณ  ๊ฐ€๋…์„ฑ ๋˜ํ•œ ๋งŽ์ด ๋–จ์–ด์ ธ์„œ ์ด๋ ‡๊ฒŒ ์ž‘์—…ํ–ˆ๋‹ค. ์ •๋ง ๊ฐ„๋‹จํ•œ read ์ž‘์—…์ด์ง€๋งŒ ๋งจ ๋•…์— ๊ตฌ๊ธ€๋งํ•˜๋ฉด์„œ ์ฝ”๋“œ๋ฅผ ์งœ์„œ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ ธ๋˜ ๊ธฐ์–ต์ด ๋‚œ๋‹ค.

์‹ค์‹œ๊ฐ„ ํšŒ์˜

๋””์ž์ด๋„ˆ ๋ฏผ์„œ๋‹˜์ด 3์ฐจ์— ๊ฑธ์ณ์„œ ์ตœ์ข…์ ์ธ ํŽ˜์ด์ง€ ๊ตฌ์„ฑ์„ ์™„๋ฃŒํ•˜์…จ๋‹ค. ์ด ํŒŒ์ผ์„ ๋ณด๋ฉด์„œ ๋””์ž์ธ์˜ ์˜๋„๋ฅผ ์„ค๋ช… ๋“ค์œผ๋ฉด์„œ ๋””์ž์ธ๊ณผ ๊ด€๋ จ๋œ ๋…ผ์˜๋Š” ๋๋‚˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์ด์–ด์„œ ์—ฌ๋ฆ„๋‹˜๊ป˜ ๋ถ€ํƒ๋“œ๋ ธ๋˜ `์ „์ž๊ธฐ๊ธฐ ๋ณ„ ํ‰๊ท ์ ์ธ ์†Œ๋น„ ์ „๋ ฅ ์กฐ์‚ฌ ํŒŒ์ผ`์„ ๋ฐ›๊ณ  ๊ด€๋ จ ์„ค๋ช…์„ ๋“ค์—ˆ๋‹ค. ํ”„๋ก ํŠธ ์ •๋ฏผ๋‹˜๊ณผ ์„œ๋ฒ„ ํŒŒํŠธ๋ฅผ ๋งก์€ ๋‚˜๋„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ด์Šˆ์— ๋Œ€ํ•ด์„œ ๋‚˜๋ˆ„์—ˆ๋‹ค. ์ตœ์ข… ๋ฐœํ‘œ ์˜์ƒ ์ œ์ถœ๊ณผ ๊ด€๋ จํ•ด์„œ ์—ญํ• ์„ ๋ถ„๋‹ดํ•œ ๋’ค ํšŒ์˜๋ฅผ ์ข…๋ฃŒํ–ˆ๋‹ค.

โœจ 02.05: ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ

PR #17 add 60% process

ํ”„๋ก ํŠธ ๊ตฌํ˜„ ์†๋„๋ณด๋‹ค ๋ฐฑ์—”๋“œ ๊ตฌํ˜„ ์†๋„๊ฐ€ ๋” ๋นจ๋ž๋‹ค. ํ”„๋ก ํŠธ์™€ ๋ฐฑ์—”๋“œ๊ฐ€ ๋งŽ์ด ์œ ๊ธฐ์ ์œผ๋กœ ์—ฐ๋™๋˜๋Š” ํ”„๋กœ์ ํŠธ์˜ ๊ฒฝ์šฐ, ๋ณดํ†ต ํ”„๋ก ํŠธ๋ฅผ ๋จผ์ € ๋Œ€์ถฉ ๊ตฌํ˜„ํ•œ ๋’ค ๋ฐ์ดํ„ฐ๋ฅผ ์ž…ํžˆ๋Š” ์‹์œผ๋กœ  ์ž‘์—…ํ•ด์™”๋‹ค. ํ•ด๋‹น ํ”„๋กœ์ ํŠธ๋„ ์•ž์„œ ์„ค๋ช…ํ•œ ๊ฒฝ์šฐ์— ์†ํ–ˆ๋Š”๋ฐ, ์ด๋ฒˆ์—๋Š” ๋””์ž์ด๋„ˆ๋ถ„๊ป˜์„œ ์ œ์‹œํ•ด์ฃผ์‹  ํŽ˜์ด์ง€๋ฅผ ํ† ๋Œ€๋กœ ๋ฐฑ์—”๋“œ ๋กœ์ง์„ ๋จผ์ € ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ณต์žกํ•˜๊ฒŒ ํŒŒ์ผ์ด ๋งŽ์•„์ ธ๋ฒ„๋ ธ๋‹ค. ์ด์™€ ๊ด€๋ จ๋œ ๋‚ด์šฉ์„ ์•ˆ๋‚ดํ•ด๋“œ๋ฆด ํ•„์š”๋ฅผ ๋Š๊ปด์„œ ํ”„๋ก ํŠธ ์ •๋ฏผ ๋‹˜์ด ๋ณด๊ธฐ ์‰ฝ๊ฒŒ ๊ทธ๋ฆผ์„ ํ•œ ์žฅ ๊ทธ๋ ค์„œ pr์— ๊ทธ๋ฆผ๋„ ์ฒจ๋ถ€ํ–ˆ๋‹ค.  ์ด์ œ ์™€์„œ ์ƒ๊ฐํ•˜๋‹ˆ xd ๋ผ๋Š” ์•„์ฃผ ๋˜‘๋˜‘ํ•œ ํˆด์„ ์“ฐ๊ณ  ์žˆ๋Š”๋ฐ ์™œ ์†์ˆ˜ ์ž‘์„ฑํ–ˆ๋‚˜ ์‹ถ๋‹ค.

 

๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์—…ํ•œ ๋‚ด์šฉ์„ ๋ฆฌ์ŠคํŠธ์—… ํ•ด๋ณด์•˜๋‹ค.

  • /calendar ์ด๋™ ์‹œ ํ˜„์žฌ ๋…„๋„ ํ•จ์ˆ˜๋กœ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
  • user collection ์˜ db ๋ชจ๋ธ๋ง ํ•˜๊ธฐ
  • /crud ๋ฐ”๋€ db ๋ชจ๋ธ์— ๋งž์ถฐ create ๋ฌธ ์ˆ˜์ •ํ•˜๊ธฐ
  • /my_power  ์ „ ๋‹ฌ์˜ ์†Œ๋น„ ์ „๋ ฅ๊ณผ ํ˜„์žฌ ์†Œ๋น„ ์ „๋ ฅ 
  • /my_power2 ํŽ˜์ด์ง€ ์ƒ์„ฑํ•˜๊ธฐ
  • /my_town ์œ ์ €(์œ ์ €์˜ ๋„์‹œ) ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
  • /home ์œ ์ € ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ณ , ๋„ค๋น„๊ฒŒ์ด์…˜ ์—ญํ• ์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€ ์—ฐ๊ฒฐํ•˜๊ธฐ

db๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ”๋€Œ์—ˆ๋‹ค.

user (collection) ใ…ก uid (document) ใ…ก 2021-02 (collection) ใ…ก device (document) ํ˜•์‹์œผ๋กœ ์ด์–ด์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ํ…Œ์ŠคํŒ…ํ•ด๋ณด๋ฉด์„œ ์ด ๋ชจํ˜•์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๊ณ„์‚ฐํ•˜๋Š” ์ž‘์—…์„ ํ•  ๋•Œ ํŽธํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ด์„œ ์ด๋ ‡๊ฒŒ ์ง„ํ–‰ํ–ˆ๋‹ค.  2~3๋ฒˆ ์ •๋„ ๊ฐˆ์•„์—Ž์—ˆ๋˜ ๊ฑธ๋กœ ๊ธฐ์–ตํ•œ๋‹ค.

 

์œ„ ์ž‘์—…๋“ค ์ค‘ ๊ฐ€์žฅ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ ธ๋˜ ํŽ˜์ด์ง€๋Š” /my_power ํŽ˜์ด์ง€์ด๋‹ค.

๋‚˜์˜ ๊ฒฝ์šฐ์—, ๋ฐ์ดํ„ฐ๋ฅผ 2๋ฒˆ ์ฝ์–ด์˜ค๋Š” ์ž‘์—…์„ ํ•˜๋Š”๋ฐ StreamBuilder๋ฅผ 2๋ฒˆ ์“ฐ๋„๋ก ์ž‘์—…ํ–ˆ๋‹ค. ๊ธฐ์กด์— ํ•œ ๋ฒˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ฌ ๋•Œ StreamBuilder๋ฅผ ์ผ๋˜ ๊ฒƒ์„ ๋ณ€ํ˜•ํ•ด์„œ ์ผ๋‹ค. ๊ตฌ๊ธ€๋ง์„ ํ† ๋Œ€๋กœ ์ตœ๋Œ€ํ•œ ์‰ฝ๊ฒŒ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ–ˆ๊ณ  ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์ธ์ง€๋Š” ์ž˜ ๋ชจ๋ฅด๊ฒ ๋‹ค. ๋‚˜๋Š” ์ด ๋ฌธ์ œ๋กœ ๊ฝค ๊ณ ์ƒ์„ ํ–ˆ๋˜ ๊ธฐ์–ต์ด ์žˆ์–ด์„œ ์ฝ”๋“œ ์ „๋ฌธ์„ ์ฒจ๋ถ€ํ•ด๋‘”๋‹ค.

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'my_power_page_view.dart';

class MyPowerPage extends StatefulWidget {
  final String date;
  num total = 0;
  MyPowerPage (this.date);

  @override
  _MyPowerPageState createState() => _MyPowerPageState();
}

class _MyPowerPageState extends State<MyPowerPage> {
  FirebaseFirestore firestore = FirebaseFirestore.instance;
  FirebaseAuth auth = FirebaseAuth.instance;
  Stream<QuerySnapshot> currentStream;

  void initState() { // [1] ์ง€๋‚œ ๋‹ฌ์˜ ์ „๋ ฅ ์†Œ๋น„๋Ÿ‰ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
    super.initState();
    currentStream =
        firestore.collection('user').doc(auth.currentUser.uid).collection(widget.date).snapshots();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StreamBuilder(
        stream: currentStream,
        builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
          if (!snapshot.hasData) {
            return CircularProgressIndicator();
          }
          // [2] lastMonth์˜ total ๊ณ„์‚ฐํ•˜๊ธฐ
          snapshot.data.docs.forEach((element) {
            widget.total += element['calculate'];
          });
          return initCurrent(); // [3] initCurrent() ํ˜ธ์ถœํ•˜๊ธฐ
        },
      ),
    );
  }
  
  initCurrent() { // [4] ํ˜„์žฌ ๋‹ฌ์˜ ์ „๋ ฅ ์†Œ๋น„๋Ÿ‰์„ order์— ๋งž๊ฒŒ ๋ถˆ๋Ÿฌ์™€ view์— ๋ฐ์ดํ„ฐ ๋„˜๊ฒจ์ฃผ๊ธฐ
    Stream<QuerySnapshot> document =
    firestore.collection('user').doc(auth.currentUser.uid).collection(widget.date)
        .orderBy('calculate', descending: true).snapshots();

    return StreamBuilder(
      stream: document,
      builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
        if (!snapshot.hasData) {
          return CircularProgressIndicator();
        } return MyPowerPageView(widget.date, snapshot.data.docs, widget.total);
      },
    );
  }
}

 

์ •๋ง ๋งŽ์€ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ž‘์—…์„ ํ•ด๋‘์–ด์„œ ๋‚˜์กฐ์ฐจ๋„ ์ปค๋ฐ‹ ๋‹จ์œ„๋ฅผ ์–ด๋–ป๊ฒŒ ์ชผ๊ฐœ์„œ ์–ด๋–ค ๋ฉ”์„ธ์ง€๋ฅผ ์ ์–ด์•ผ ํ•  ์ง€ ๊ณ ๋ฏผ์„ ๋งŽ์ด ํ•˜๊ฒŒ ๋  ๊ฒƒ ๊ฐ™์•„ ๋ฌดํ„ฑ๋Œ€๊ณ  ํ•œ๊บผ๋ฒˆ์— ์ปค๋ฐ‹ํ•ด๋ฒ„๋ ธ๋Š”๋ฐ ๋” ๊ณ ๋ฏผํ•ด๋ณด๊ณ  ์ ์„ ๊ฑธ ๊ทธ๋žฌ๋‹ค. ์ฝ”๋“œ ์ž‘์„ฑํ–ˆ๋˜ ๊ณผ์ •์ด ์ž˜ ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š์•„ ์•„์‰ฌ์›€์„ ๋‚จ๋Š”๋‹ค.

์‹ค์‹œ๊ฐ„ ํšŒ์˜

๋‹ค์Œ ๋‚  ๊ตฌํ˜„ ๋ฐ๋ชจ ์˜์ƒ์„ ์ œ์ถœํ•ด์•ผ ํ•ด์„œ ์˜์ƒ ์ œ์ž‘์„ ๋งก์œผ์‹  ๋ฏผ์„œ๋‹˜๊ป˜์„œ ์ง„ํ–‰ ์ƒํ™ฉ์— ๋Œ€ํ•ด์„œ ์—ฌ์ญค๋ณด์…จ์—ˆ๋‹ค. ๊ธˆ์š”์ผ๋‚  10์‹œ 20๋ถ„๋ถ€ํ„ฐ ์ง„ํ–‰ํ•œ ํšŒ์˜๊ฐ€ ๋‚œ ์•„์ง๋„ ์ƒ์ƒํ•˜๋‹ค. ํšŒ์˜์—์„œ ๋‚ด๊ฐ€ ํ˜„์žฌ๊นŒ์ง€ ๊ตฌํ˜„๋œ ์–ดํ”Œ ์‹œ์—ฐ๊ณผ ํ•จ๊ป˜ ์ง„ํ–‰ ์ƒํ™ฉ์„ ์ž์„ธํžˆ ์„ค๋ช…ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ € ์งˆ๋ฌธ์—๋Š” ๋‚˜๋„ ๋‚ด๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„์ง€ ๊ฐ์ด ์•ˆ์žกํ˜€์„œ ๋ถˆ์•ˆํ•œ ๊ฐ์ •์˜ ์—ฐ์†์ด์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‹ค์Œ ๋‚  9์‹œ ์ •๋„๊นŒ์ง€ ๊ตฌํ˜„๋œ ๋‚ด์šฉ์œผ๋กœ ๊ธฐ๋Šฅ ๋ฆฌ์ŠคํŠธ ์—… ํ•œ ํ›„ ๊ธฐ๋Šฅ ๊ด€๋ จ ๋Œ€๋ณธ์„ ์ง ๋‹ค๊ณ  ํ•˜์…จ๋‹ค.

โœจ 02.06: ๋ฐค์ƒ˜, ์ œ์ถœ

์ด์   ๋” ์ด์ƒ ๋ฌผ๋Ÿฌ๋‚  ๊ณณ์ด ์—†์—ˆ๋‹ค. ์™„์„ฑ ๋ชปํ•œ ๊ธฐ๋Šฅ์€ ์ˆ˜๋‘๋ฃฉ์ธ๋ฐ ์™„์„ฑ์„ ํ•ด์•ผ ํ–ˆ๋‹ค. ์—ด์‹ฌํžˆ ๋‹ฌ๋ ธ๋‹ค !

PR #19 add update, delete logic, calculate logic

์œ„ ํŽ˜์ด์ง€์˜ update ๊ธฐ๋Šฅ

firestore
          .collection('electronics').where("device", isEqualTo: device).get()
          .then((QuerySnapshot ds) {
        var defaultValue = ds.docs[0]['Wh'];
        firestore
            .collection('user')
            .doc(auth.currentUser.uid)
            .collection(_getCurrentYearAndMonth())
            .doc(device)
            .set({
          'device': device,
          'usage_time': double.parse(time),
          'calculate': double.parse(time) * double.parse(defaultValue)
        }).then((value) {
          Navigator.pushReplacementNamed(context, '/crud');

update์˜ ๊ฒฝ์šฐ create๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ์™€ 100% ์ฝ”๋“œ๊ฐ€ ๋™์ผํ•˜๊ฒŒ ์จ๋„ ์ž‘๋™์„ ํ•œ๋‹ค. firebase์˜ ๋˜‘๋˜‘ํ•œ ๋ถ€๋ถ„์„ ๋Š๋‚„ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๋ฐ”๋žŒ์—, created_date ์™€ modified_date ์— ๋™์ผํ•œ ๊ฐ’์ด ์ €์žฅ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ์˜ ์„œ๋น„์Šค์—์„œ๋Š” ์ˆ˜์ • ์‹œ๊ฐ„์„ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€๋„ ์—†๊ณ , ์ค‘์š”ํ•˜์ง€ ์•Š์•„์„œ ๋นผ๋ฒ„๋ ธ๋‹ค.

ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์กฐ๊ธˆ ๋” ์„ค๋ช…ํ•ด๋ณด๋ ค ํ•œ๋‹ค. ์‚ฌ์šฉํ•œ ์ „์ž๊ธฐ๊ธฐ์™€ ์‚ฌ์šฉํ•œ ์‹œ๊ฐ„์„ ์ž…๋ ฅ๋ฐ›์•„ ์ €์žฅ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์œ„์˜ ์ฝ”๋“œ๋ฅผ ํƒ„๋‹ค. 1. ์ „์ž๊ธฐ๊ธฐ์˜ ์‹œ๊ฐ„ ๋‹น ํ‰๊ท ์ ์ธ ์†Œ๋น„ ์ „๋ ฅ๋Ÿ‰์„ db์— ์ €์žฅํ•ด๋‘์—ˆ๋Š”๋ฐ ๊ทธ ๊ฐ’์„ ์ฐพ์•„์˜จ๋‹ค. 2. ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ์ •๋ณด์™€ ํ•จ๊ป˜ ์ „์ž๊ธฐ๊ธฐ๊ฐ€ ์‚ฌ์šฉํ•œ ์ „๋ ฅ ์†Œ๋น„๋Ÿ‰์„ ๊ณ„์‚ฐํ•œ ๊ฐ’์„ db์— ์ €์žฅํ•œ๋‹ค. 3. ์—…๋ฐ์ดํŠธ๋œ ์ •๋ณด๋กœ ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.

 

์œ„ ํŽ˜์ด์ง€์˜ delete ๊ธฐ๋Šฅ

    firestore
        .collection('user')
        .doc(auth.currentUser.uid)
        .collection(_getCurrentYearAndMonth())
        .doc(device)
        .delete()
        .then((value) {
      Navigator.pushReplacementNamed(context, '/crud');

์ง€์šฐ๊ณ  ์‹ถ์€ ์ •๋ณด๊ฐ€ user collection์˜ uid๋กœ ๋œ doc ์•ˆ์— ์ „์ž ์žฅ๋น„ ์ด๋ฆ„์œผ๋กœ ๋˜์–ด ์žˆ์–ด์„œ ์–ด๋ ต์ง€ ์•Š๊ฒŒ ์‚ญ์ œ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์ด ์ฝ”๋“œ๋„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ญ์ œํ•œ ํ›„ ์‚ญ์ œ๋˜์—ˆ์Œ์„ ๋ฐ”๋กœ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก Navigator.pushReplacementNamed() ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

 

์†Œ๋น„ ์ „๋ ฅ ๊ณ„์‚ฐ ๊ณผ์ •

๋‚ ์งœ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฑด ์ƒ๊ฐ๋ณด๋‹ค ๊นŒ๋‹ค๋กญ๋‹ค. ์ผ๋‹จ ์ œ๊ณตํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ์ž˜ ํ™œ์šฉํ•ด์•ผ ํ•˜๊ณ  ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ์ž˜ ์ง€์–ด์•ผํ•œ๋‹ค. ๊ทธ๋ž˜์•ผ ๊ณ„์‚ฐ์‹์„ ์“ฐ๋Š” ๊ณผ์ •์—์„œ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์„ ์ œ๋Œ€๋กœ ์‹ค์ˆ˜์—†์ด ์“ธ ์ˆ˜ ์žˆ๊ณ  ํ›„์— ์œ ์ง€๋ณด์ˆ˜๋„ ํŽธํ•  ๊ฒƒ์ด๋‹ค. ๋ฐ”๋กœ ์ง์ „ ํ•™๊ธฐ์— ์ž๋ฐ”ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐ ์‹ค์Šต ๊ณผ๋ชฉ์—์„œ ๊ธฐ๋ง์ด ์ž์œจ ํ”„๋กœ์ ํŠธ๋กœ ๋Œ€์ฒด๋˜์–ด์„œ ๋‚˜๋Š” ๋‹ฌ๋ ฅ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” gui๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ฐœ๋ฐœํ–ˆ์—ˆ๋Š”๋ฐ ๊ทธ ๋•Œ ๊ฒฝํ—˜์ด ๋„์›€์ด ๋˜์–ด์„œ ๋” ๋น ๋ฅด๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

์—ฌ๊ธฐ๊นŒ์ง€์˜ ๊ฐœ๋ฐœํ•˜๊ณ  ์˜ค์ „ 3์‹œ ์ •๊ฐ์— Pull Request๋ฅผ ๋ณด๋ƒˆ๋‹ค.

PR #20 give parameter clicked month info

์ด์ œ ์‚ฌ์šฉ์ž๊ฐ€ ํ˜ธ์ถœํ•œ ๋…„-๋‹ฌ์ด ์–ธ์ œ์ธ์ง€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„์˜ค๋Š” ์ž‘์—…๋งŒ ๋‚จ์•˜๋‹ค. ๊ทผ๋ฐ ์ด ์ž‘์—…์ด ์ •๋ง ๋งŒ๋งŒ์น˜ ์•Š์•˜๋‹ค.

"2021-02"์™€ ๊ฐ™์ด String์œผ๋กœ ํด๋ฆญํ•œ ๋‹ฌ์˜ ๊ฐ’์„ ์ธ์ž๋กœ ๋ฐ›๊ธฐ ์œ„ํ•ด์„œ onGenerateRoute ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ •์„์ ์ธ ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ํ•ด์„œ ๋„์ž…ํ•ด๋ดค๋‹ค. parameter๋กœ ์ฃผ๋Š” ๊ฒƒ ์ž์ฒด๋Š” ์–ด๋ ต์ง€ ์•Š์•˜๋Š”๋ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•ด์„œ initState์— ๊ฐ’์„ ๋„˜๊ฒจ์ฃผ์–ด์•ผ ํ•ด์„œ ๋„ˆ๋ฌด ๊นŒ๋‹ค๋กœ์› ๋‹ค.
์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์“ฐ๋ฉด ์‹คํ–‰์€ ๋˜๋Š”๋ฐ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ์ถ”์ƒ์ ์ธ ์—๋Ÿฌ ๋กœ๊ทธ๊ฐ€ ๋œฌ๋‹ค. ๊ผฌ๋ฐ• 3์‹œ๊ฐ„๋™์•ˆ ์ด ์ž‘์—…์„ ํ•˜๋ฉด์„œ stackoverflow๋ฅผ ์ •๋ง ์ •๋…ํ–ˆ๋Š”๋ฐ ๋” ์ด์ƒ ์‹œ๊ฐ„์„ ์ง€์ฒดํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ด์„œ ์ด ๋Šช์—์„œ ์ผ๋‹จ ๋ฒ—์–ด๋‚˜๊ธฐ๋กœ ํ–ˆ๋‹ค. ๋‚˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ˜„ํ–ˆ๋‹ค.

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'my_page.dart';
import 'welcome.dart';
// ... ์ƒ๋žต
import 'my_power_page.dart';
import 'my_power2_page.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MainPage());
}

class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Main Page',
      debugShowCheckedModeBanner: false,
      initialRoute: '/welcome',
      routes: {
        '/welcome': (context) => Welcome(),
        '/my_page': (context) => MyPage(),
      },
      onGenerateRoute: (RouteSettings settings) {
        var routes = <String, WidgetBuilder>{
          'my_power': (context) => MyPowerPage(settings.arguments),
          'my_power2': (context) => MyPower2Page(settings.arguments),
          // ... ์ƒ๋žต
        };
        WidgetBuilder builder = routes[settings.name];
        return MaterialPageRoute(builder: (ctx) => builder(ctx));
      },
      theme: ThemeData(
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
    );
  }
}
class MyPowerPage extends StatefulWidget {
  final String date;

  MyPowerPage(this.date); // ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ธ์ž๋ฅผ ๋ฐ›๋Š”๋‹ค.

  num totalLast = 0;
  num totalCurrent = 0;

  @override
  _MyPowerPageState createState() => _MyPowerPageState();
}

class _MyPowerPageState extends State<MyPowerPage> {
  FirebaseFirestore firestore = FirebaseFirestore.instance;
  FirebaseAuth auth = FirebaseAuth.instance;
  Stream<QuerySnapshot> currentStream;

  // [1] lastMonth ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
  void initState() {
    super.initState();
    DateInfo dateInfo = new DateInfo(widget.date); // widget.date ๋กœ ํ™œ์šฉ ๊ฐ€๋Šฅ
    currentStream = firestore
        .collection('user')
        .doc(auth.currentUser.uid)
        .collection(dateInfo.lastYear + "-" + dateInfo.lastMonth)
        .snapshots();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StreamBuilder(
        stream: currentStream,
        builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
          print(snapshot);
          if (!snapshot.hasData) {
            return CircularProgressIndicator();
          }
          // [2] lastMonth์˜ total ๊ณ„์‚ฐํ•˜๊ธฐ
          snapshot.data.docs.forEach((element) {
            widget.totalLast += element['calculate'];
          });
          return initCurrent();
        },
      ),
    );
  }
  
  // [3] currentMonth, calculate order์— ๋งž๊ฒŒ ๋ถˆ๋Ÿฌ์™€ view์— ๋„˜๊ฒจ์ฃผ๊ธฐ
  initCurrent() {
    Stream<QuerySnapshot> document = firestore
        .collection('user')
        .doc(auth.currentUser.uid)
        .collection(widget.date)
        .orderBy('calculate', descending: true)
        .snapshots();

    return StreamBuilder(
      stream: document,
      builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
        if (!snapshot.hasData) {
          return CircularProgressIndicator();
        }
        // [2] lastMonth์˜ total ๊ณ„์‚ฐํ•˜๊ธฐ
        snapshot.data.docs.forEach((element) {
          widget.totalCurrent += element['calculate'];
        });
        DateInfo dateInfo = new DateInfo(widget.date);
        if (DateFormat('yyyyMM').format(DateTime.now()) ==
            dateInfo.currentYear + dateInfo.currentMonth) {
          // ํ˜„์žฌ๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒฝ์šฐ -> ๊ณ„์‚ฐ๋ฐฉ์‹: ํ˜„์žฌ ์‚ฌ์šฉ๋Ÿ‰ - ์ „๋‹ฌ๋™์•ˆ์‚ฌ์šฉ๋Ÿ‰ * (ํ˜„์žฌ ์ผ ์ˆ˜/์ „ ๋‹ฌ์˜ ์ผ ์ˆ˜)
          var result = widget.totalCurrent -
              (widget.totalLast *
                  num.parse(dateInfo.currentDate) /
                  num.parse(dateInfo.lastMonthOfDay));
          return MyPowerPageView(widget.date, snapshot.data.docs, result);
        } else {
          // ๊ณผ๊ฑฐ์˜ ๋‹ฌ์„ ํ˜ธ์ถœํ•œ ๊ฒฝ์šฐ -> ๊ณ„์‚ฐ๋ฐฉ์‹: ๊ณผ๊ฑฐ์˜ ๋‹ฌ ์‚ฌ์šฉ๋Ÿ‰ - ๊ณผ๊ฑฐ์˜ ๋‹ฌ์˜ ์ง ์ „๋‹ฌ ์‚ฌ์šฉ๋Ÿ‰
          var result = widget.totalCurrent - widget.totalLast;
          return MyPowerPageView(widget.date, snapshot.data.docs, result);
        }
      },
    );
  }
}

์˜ค์ „ 6:46, PR ํ–ˆ๋‹ค.

PR #21 fix bug

์˜ค์ „ 8:02, ๋ฐœํ‘œ ๋Œ€๋ณธ์„ ์จ์ฃผ์‹œ๋Š” ๋ฏผ์„œ ๋‹˜๊ป˜ ์—ฌ๊ธฐ๊นŒ์ง€ ๊ตฌํ˜„๋œ ๊ธฐ๋Šฅ์„ ๋ฆฌ์ŠคํŠธ ์—… ํ•ด์„œ ๋ณด๋‚ด๋“œ๋ ธ๋‹ค.

PR #23 fix bug

์˜ค์ „ 11:42, Pull Request๋ฅผ ๋ณด๋ƒˆ๊ณ  ์—ฌ๊ธฐ๊นŒ์ง€๋กœ ๊ธฐ๋Šฅ ๊ตฌํ˜„์€ ๋งˆ๋ฌด๋ฆฌํ–ˆ๋‹ค.

PR #25~26 apply font, Style up

๋ฐ๋ชจ ์˜์ƒ์„ ์ฐ์œผ๋ ค๊ณ  ํ•˜๋Š”๋ฐ ๊ธฐ๋Šฅ์€ ์ž˜ ๋ณด์ด์ง€๋งŒ ํ”„๋ก ํŠธ์—์„œ ๊ฑฐ์Šฌ๋ฆฌ๋Š” ๋ถ€๋ถ„์ด ๋งŽ์•˜๋‹ค. ๋จผ์ € NanumSquare ํฐํŠธ๋ฅผ ์ ์šฉํ–ˆ๋Š”๋ฐ ํฐํŠธ๋ฅผ ์ ์šฉํ•˜์ž๋งˆ์ž ๋‚ด๊ฐ€ ํ–ˆ๋˜ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋งž๋‚˜ ์‹ถ์„ ์ •๋„๋กœ ๋„ˆ๋ฌด ์˜ˆ๋ป์ ธ์„œ ๊ฐ€์Šด์ด ์›…์žฅํ•ด์กŒ๋‹ค ใ… _ใ…  ํ”„๋ก ํŠธ๋Š” ๊ฑฐ์˜ ๋ชจ๋ฅด์ง€๋งŒ ์ง€๊ธˆ๊นŒ์ง€ ๊ตฌํ˜„๋œ ์ฝ”๋“œ์™€ ๋ˆˆ์น˜๊ป ์ž˜ ํ™œ์šฉํ•ด ํ™”๋ฉด ์ˆ˜์ •๊ณผ ๋™์‹œ์— ๋ฐ๋ชจ ์˜์ƒ์„ ๋ถ€๋ถ„์ ์œผ๋กœ ์ฐ์–ด ๋“œ๋ ธ๋‹ค. ๋‹ค์‹œ ๋‚ด์—ญ๋“ค์„ ๋ณด๋‹ˆ ํ”„๋ก ํŠธ๋„ ์ƒ๊ฐ๋ณด๋‹ค ๋งŽ์ด ๊ณ ์ณค๋‹ค !

PR #29 end of hackathon, ์ œ์ถœ

  • feat(crud): update dropdownbar to textfield - /crud ํŽ˜์ด์ง€์—์„œ ์‚ฌ์šฉ ์‹œ๊ฐ„์„ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ž…๋ ฅ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •
  • ์ด ์™ธ ์ฝ”๋“œ ์Šคํƒ€์ผ ๋งž์ถ”๊ธฐ, ํ•„์š” ์—†๋Š” ํŽ˜์ด์ง€ ์‚ญ์ œ

์ด๋กœ์จ ์˜คํ›„ 4์‹œ 23์œผ๋กœ ํ•ด์ปคํ†ค ๋งˆ๊ฐ ์‹œ๊ฐ„์ธ 5์‹œ ์ด์ „์œผ๋กœ ๋งˆ์ง€๋ง‰ pr๋ฅผ ๋ณด๋ƒˆ๋‹ค. ๋ญ ๋จน์„ ์—ฌ์œ ๋„ ์—†์—ˆ๋Š”๋ฐ ๋ฐฅ ๋ช‡ ์ˆŸ๊ฐ€๋ฝ ๋œจ๊ณ  ๋ฐ”๋กœ ๊ฐ€์„œ ์žค๋˜ ๊ธฐ์–ต์ด ๋‚œ๋‹ค.

โœจ 02.07: ๋ณด์™„

PR #30 link calendar data and fix bugs

๋‹ค์Œ๋‚  ์ผ์–ด๋‚˜ ๋‹ค์‹œ ์–ดํ”Œ์„ ์‹คํ–‰ํ•ด๋ดค๋Š”๋ฐ ์•„์‰ฌ์šด ๋ถ€๋ถ„๋“ค์ด ๋ˆˆ์— ๋ฐŸํ˜”๋‹ค. ๊ทธ๋ž˜์„œ ๋‹ค์‹œ ์ปดํ“จํ„ฐ๋ฅผ ์ผœ์„œ ์ด์–ด์„œ ์กฐ๊ธˆ ์ž‘์—…ํ–ˆ๋‹ค.

  • ์บ˜๋ฆฐ๋”์—์„œ ๋…„๋„ ์ด๋™ ํ›„ ํ•ด๋‹นํ•œ ๋…„๋„์˜ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๋Š” ๋ฒ„๊ทธ ์ˆ˜์ •
  • crud ํŽ˜์ด์ง€์—์„œ ๋’ค๋กœ๊ฐ€๊ธฐ๋ฅผ ๋ˆ„๋ฅด๋ฉด ๋‚˜์˜ค๋Š” ํ™ˆํŽ˜์ด์ง€์—์„œ์˜ ์ •๋ณด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ณ„์‚ฐ๋˜์ง€ ์•Š์•˜๋˜ ๋ฒ„๊ทธ ์ˆ˜์ •
    • ์ด ๋ถ€๋ถ„์€ ๊ตฌ๊ธ€๋งํ•ด์„œ onWillPop์„ ๋„์ž…ํ•ด๋ดค๋‹ค.
    return new WillPopScope (// ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ๋ˆŒ๋ €์„ ๋•Œ
      onWillPop: () {  // ์Œ“์ธ ์œ„์ ฏ์„ ์‚ญ์ œํ•˜๊ณ  ํ™ˆ์œผ๋กœ ์ด๋™(๋ฐ์ดํ„ฐ์ƒˆ๋กœ๋ถˆ๋Ÿฌ์™€์•ผํ•ด์„œ)
        Navigator.pushNamedAndRemoveUntil(context, '/home', (route) => false);
        return;
      },
  • ์–ด๋–ค ์ˆœ์„œ๋กœ ์ •๋ ฌ๋œ ํŽ˜์ด์ง€์ธ์ง€ ์•Œ๋ ค์ฃผ๋„๋ก ํƒ€์ดํ•‘ ์ˆ˜์ •
    • ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค ์ •๋ณด๋ฅผ ๋ณด๊ณ  ์žˆ๋Š”์ง€ ๋” ์ง๊ด€์ ์œผ๋กœ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ์•„๋ž˜์™€ ๊ฐ™์ด ๊ณ ์ณค๋‹ค.

๋Š๋‚€ ์ 

๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ๋งค์ผ ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ์ƒ๊ฐ๋ณด๋‹ค ๋„ˆ๋ฌด ์™„์„ฑ๋„ ์žˆ๊ฒŒ ๋งˆ๋ฌด๋ฆฌ ๋˜์—ˆ๋‹ค. (์ ์–ด๋„ ๋‚˜๋Š” ๊ทธ๋ ‡๊ฒŒ ์ƒ๊ฐํ•œ๋‹ค...!) ๊ทธ๋ž˜์„œ ๋‚˜๋„ ๋‚ด๊ฐ€ ์‹ ๊ธฐํ–ˆ๋‹ค. ์–ด๋ผ? ์ง„์งœ ๋‚ด๊ฐ€ ๊ฐœ๋ฐœ์„ ํ•˜๊ณ  ์žˆ๋„ค? ๊ฐ€ ์ „์ฒด์ ์ธ ํ›„๊ธฐ์ด๋‹ค. ๊ทธ๋™์•ˆ ๊ฐœ๋ฐœ ์ž์ฒด๊ฐ€ ์‚ฌ์‹ค ๋ฌด์—‡์ธ์ง€ ์ž˜ ๊ฐ๋„ ์•ˆ์˜ค๊ณ  ๋ฐฐ์›€์˜ ๋์ด ๋ณด์ด์ง€ ์•Š์•„์„œ ์ง€์น  ์ฆˆ์Œ์ด์—ˆ๋Š”๋ฐ ์„ฑ์žฅ ๊ฐ€๋Šฅ์„ฑ์„ ๋Š๋‚„ ์ˆ˜ ์žˆ์—ˆ๋˜ ์†Œ์ค‘ํ•œ ์‹œ๊ฐ„์ด ๋˜์—ˆ๋‹ค. ๋ง‰์ค‘ํ•œ ์ฑ…์ž„๊ฐ์œผ๋กœ ํž˜๋“ค์—ˆ๋˜ ๊ฑด ์‚ฌ์‹ค์ด์ง€๋งŒ ๋‹จ ์‹œ๊ฐ„์— ์„ฑ์žฅํ•ด๋ฒ„๋ฆฐ ๊ธฐ๋ถ„์ด๋‹ค. ์ด ์„ฑ์žฅํ•˜๋Š” ๋Š๋‚Œ์ด ์ •๋ง ์งœ๋ฆฟํ•˜๋‹ค. ์ •๋ง ์ž‘์€ ๋กœ์ง๋ถ€ํ„ฐ ํ•˜๋‚˜์”ฉ ๊ตฌํ˜„ํ–ˆ์„ ๋•Œ ๋ฐ€๋ ค์˜ค๋Š” ์„ฑ์ทจ๊ฐ์ด ๋‹ค์‹œ ๋™๋ ฅ์ด ๋˜๋Š” ๊ฑธ ๋Š๊ผˆ๋‹ค. ์ด๊ฑด ๋งˆ์น˜ ๋ฌดํ•œ ๋™๋ ฅ์ด ์•„๋‹๊นŒ ์‹ถ์€ ๊ธฐ๋ถ„์ด์—ˆ๋‹ค. ์•„... ์ด๋ž˜์„œ ๊ฐœ๋ฐœ์ž๋ฅผ ํ•˜๋‚˜๋ณด๋‹ค. ํž˜๋“ค์ง€๋งŒ ์ •๋ง ๋งค๋ ฅ ์žˆ๋Š” ์ง์—…์ด๋‹ค.

 

๊ทธ๋™์•ˆ ๋„ˆ๋ฌด ํž˜๋“ค๊ฒŒ ์‚ฝ์งˆํ–ˆ๋˜ ์•„์ฃผ ์ž‘์€ ๊ฒฝํ—˜ ๊ฒฝํ—˜๋“ค์ด ํ™•์‹คํžˆ ๋„์›€์ด ๋˜์—ˆ๋‹ค. db ๋ณด๋ฉด ํšŒ์› ๊ฐ€์ž… ์‹œ ์ƒ์„ฑ๋œ ์œ ์ €์˜ ๊ณ ์œ ์•„์ด๋””(uid)๋ฅผ user collection์˜ document ์ด๋ฆ„์œผ๋กœ ๋งค์šฐ ์ค‘์š”ํ•˜๊ฒŒ ์“ฐ๊ณ  ์žˆ๋Š”๋ฐ, ์ด์ „์— ํ”„๋กœ์ ํŠธํ•˜๋ฉด์„œ ์ด๊ฑฐ ์ €์žฅํ•˜๋Š”๋ฐ๋งŒ ์ง„์งœ๋กœ 24์‹œ๊ฐ„ ์‚ฝ์งˆํ–ˆ์—ˆ๋‹ค. ๊ผฌ๋ฐ• ํ•˜๋ฃจ๋ฅผ ์˜จ์ „ํžˆ! ์“ฐ๊ณ  ๋‹ค์Œ๋‚  ์ผ์–ด๋‚˜์„œ๋„ 8์‹œ๊ฐ„์€ ์ €๊ฒƒ๋งŒ ์ฐพ์•„๋ดค๋‹ค. ๊ทธ ๋•Œ๋Š” ์ •๋ง ์ €๊ฒƒ ๋•Œ๋ฌธ์— ์˜จ๊ฐ– ์š•์€ ๋‹ค ํ•˜๊ณ  ๋ฏธ์น  ๋ป” ํ–ˆ๋˜... ๊ธฐ์–ต์ด ๋งค์šฐ ์ƒ์ƒํ•˜๋‹ค. ๋‚˜์ค‘์— ๋˜ firebase ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๊ฒŒ ๋ ์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ์ด ๋•Œ ๊ฐœ๋ฐœํ–ˆ๋˜ ์ฝ”๋“œ ์กฐ๊ฐ์กฐ๊ฐ์ด ํ•„์š”ํ•ด์ง€๋Š” ๋‚ ์ด ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.

 

ํ‰์†Œ java๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๊ฐ€ dart๋ž€ ์ƒˆ๋กœ์šด ์–ธ์–ด๋ฅผ ์ ‘ํ•˜๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ, ์–ธ์–ด๊ฐ€ ๋‹ฌ๋ผ๋„ ์‚ฌ์‹ค ์ œ๊ณตํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ๋“ค์ด ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์•„์„œ ๋ˆˆ์น˜๊ป ์˜ค๋ฅ˜ ๋นจ๊ฐ„์ค„ ์•ˆ๋œจ๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด ๋Œ์•„๊ฐ”๋‹ค. ์ด ๋ถ€๋ถ„๋„ ์‚ฌ์‹ค ์ข€ ์‹ ๊ธฐํ–ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๊ณ  ๋‹น์—ฐํ•œ ๋ง์ด์ง€๋งŒ ์ž˜ ๋‹ค๋ฃฌ๋‹ค๋Š” ๊ฑด ์•„๋‹ˆ๋‹ค. ๋‹ค์‹œ flutter๋กœ ๊ฐœ๋ฐœํ•  ๊ธฐํšŒ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๊ฐœ๋… ํ›‘์–ด์ฃผ๋Š” ์ฑ…์ด๋‚˜ ๊ฐ•์˜๋ฅผ ๋‹ค์‹œ ๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์งˆ ๊ฒƒ์ด๋‹ค.๊ฒฝํ—˜์€ ํ•ด๋ดค์œผ๋‹ˆ ๋น ๋ฅด๊ฒŒ ์ตํžˆ๊ณ  ๋” ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ฆฌ๊ณ  js ์˜ es ๋ฌธ๋ฒ•๋“ค์€ ์ตํžˆ๊ณ  ์žˆ์–ด์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค. ํ•™๊ธฐ๊ฐ€ ์‹œ์ž‘ํ•˜๊ณ  ์‹œ๊ฐ„์ด ๋‚˜๋ฉด ํ‹ˆํ‹ˆํžˆ ๊ฐ„๋‹จํžˆ ๊ณต๋ถ€ํ•  ๊ฒƒ์ด๋‹ค. 

 

๋งˆ์ง€๋ง‰์œผ๋กœ ํŒ€๋„ ์ž˜ ๋งŒ๋‚œ ๊ฒƒ ๊ฐ™๋‹ค ! ์—ด์ • ๊ฐ€๋“ํ•˜์‹  ์ •๋ฏผ๋‹˜ ๋•๋ถ„์— ์ง€์น˜์ง€๋งŒ ํ”„๋ก ํŠธ ๊ตฌํ˜„ํ•˜๊ณ  ๊ณ„์‹ค ์ •๋ฏผ๋‹˜ ์ƒ๊ฐํ•˜๋ฉด์„œ ์ปดํ“จํ„ฐ ์•ž์— ์•‰์•„์žˆ์„ ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค. ๋งค์ผ ์˜จ๋ผ์ธ์œผ๋กœ ์‚ฌ์ง„์€ ์ฐ์—ˆ๋Š”๋ฐ ์‹ค์ œ๋กœ ๋ต ๊ธฐํšŒ๊ฐ€ ์ƒ๊ฒผ์œผ๋ฉด ์ข‹๊ฒ ๋‹ค *-*