ㅤ 지금까지는 이미지를 네트워크에서 받아올 때에 FutureBuilder를 통해 에셋이미지를 로드하고, 이를 그려주는 방식으로 적용하고 있었다. 아무래도 Image 위젯 바깥에서 FutureBuilder로 이미지 에셋을 확인하고, 이를 Image 위젯으로 넣어주는 방법이다보니, 이미지와 관련된 로직이 Image 위젯 내에서 딱 처리가 된다는 느낌이 없어서 코드가 지저분하다고 느꼈었다. ㅤ FutureBuilder( // imageFuture가 불러와질 때 까지 아래의 위젯들을 조건에 맞게 보여주기 future: widget.imageFuture, builder: (context, snapshot) { // 데이터를 불러온 경우 if (snapshot.hasData) { return Image(snapsh..
ㅤ 이번에는 또 기묘한 UI를 만났다. ㅤ Flutter의 AppBar는 색상이 반투명한 글래스모피즘처럼 적용되어서, 아래로 스크롤을 올리니 자동으로 색이 반영되는 UI가 기본으로 있었다. 아래 GIF를 확인해보면, 상단 AppBar의 색이 움찔움찔 변경되는 것을 확인할 수 있다. ㅤ 나의 경우에는 바로 아래에 있는 캘린더도 AppBar 쪽에 붙어있기 때문에, 색이 끊겨보여서 이를 제거해주고 싶었다. 그러나, ‘flutter remove appbar background color changed on scroll’ 같은 검색어로 검색했는데, 해결 방법이 잘 나오지 않더라. ㅤ 설마 없겠어? 라고 생각을 하면서 AppBar 위젯의 어트리뷰트를 하나하나 찬찬히 뒤져보면서 해결 방법을 찾았다. AppBar( b..
ㅤ 오늘도 간단한 문제로 3시간을 날렸다. 이전 글에서 SwiftUI의 FullscreenCover 방식의 화면전환을 사용하려면 fullscreenDialog를 사용하면 된다고 했었는데, 여기와 관련된 문제가 발생했다. ㅤ 아래와 같은 구조로 되어있고, 화살표처럼 화면 전환을 만들고자 했다. ㅤ 여기에서, fullscreen dialog로 넘어간 2번째 줄에서는 push로 페이지를 전환한 다음에는 뒤로 pop을 할 수 없는 구조이기에 pushReplacement 같은 함수를 사용해 전환하려고 고려하고 있었다. ㅤ 그러나, fullscreenDialog 첫 페이지에서 pushReplacement 함수를 호출하니, bottomSheet 이 있는 뷰로 가버리는 문제가 있었다! 아마 추측하건데, fullscre..
ㅤ 아래와 같은 화면 전환 기능을 구현하고 싶었다. SwiftUI 에서는 아래 기능을 Fullscreen Cover 라고 부른다. 오른쪽 왼쪽으로 화면이 전환되는 Navigation과 달리 수직으로 올라오는 애니메이션이 특징이며, 모달과 달리 머리를 잡고 아래로 스크롤해도 전환이 취소가 되지 않는다. 주로 일시적인 데이터 입력이나 흐름을 벗어나서 유저가 확 집중을 해야하는 부분에서 이러한 방식을 사용한다. ㅤ ㅤ 뭔가 Navigator.push() 처럼 Navigator 하위에 함수가 있을 것이라고 생각했는데, 찾아보니 없었다. 그래서 아예 모달을 불러오는showBottomModalSheet() 함수처럼 아예 별개의 함수로 있을 거라고 생각해서 구글링을 해봤다. 그런데 띠용? Navigator.push ..
오늘도 쌩고생을 했다. 매주 쌩고생거리가 계속 등장하는 것 같다. ㅜㅜ 심지어 오늘은 다트 문법에 당했다. ㅤ List 뒤에 원소를 추가하고 싶을 때는 append가 아닌 add 함수를 사용해야 한다. 블로그 글을 쓰기 위해서 가져왔는데, 이제야 함수의 차이점이 보인다. ㅤ append 쪽 설명을 읽어보면 “Insert element at the end of the [Iterable]” 이라고 되어있다. 나는 요걸 보고 철썩같이 믿고 썼는데, 아무리 디버깅을 해도 해결이 안돼서 한숨만 푹푹 쉬고 있었지… 근데 요게 문제였을 줄은 몰랐다… 파이어베이스에 복잡하게 쿼리를 날리고 결과를 조인해야 하는 기능이라 중간에 뭐가 잘못되었는지 디버거 켜놓고 값 계속 확인하면서 찾아나섰는데, 제일 마지막에 결과 합쳐서 ..
ㅤ 최근에 해결하는데에 꼬박 4일이 걸린 문제가 있었다 ㅜㅜㅜㅜㅜ ㅤ 뷰에서 작은 컴포넌트 위젯에서 GestureDetector를 통해 PanGesture를 인식하고, 터치 좌표값을 받아다가 뷰에게 전달하고, 뷰에서 이를 받아다가 setState로 값을 수정하면 다른 위젯에서 이 값으로 UI를 그리는 로직을 작성하고 있었다. 대충 그림으로 그리면 아래와 같다. ㅤ 이를 위해서 대략적으로 아래 플로우로 실행을 제어하려고 했다. View에서 GestureDetector가 달린 위젯에 콜백함수를 전달 onPanUpdate 시 콜백함수 호출 콜백함수에서 setState 실행 뷰 다시 그리기 position UI 반영 ㅤ 그런데 왠걸? onPanUpdate 함수가 1-2번 호출되고나면 콜백함수가 더 이상 실행되지..
ㅤ 처음에 클린 아키텍처를 프로젝트에 반영하려고 하면서 어떻게 구조를 설계해야하나 고민을 할 때, 아래같은 내용을 담은 적이 있었다. 그리고, 이게 다시 한 번 불편하다고 느낀 상황이 와버렸다! ㅋㅋㅋ ㅤ 아래 이미지처럼 import 문의 크기를 줄이기 위해 열심히 GBDF를 적용해 간소화를 적용하고 있었다. ㅤ 그런데, 저렇게 줄이고 나니깐 각 파일에서 어떤 계층을 참고하고 있는지 더 선명하게 보이기 시작했다. 다시 말하자면, domain 모델에서도 data 계층의 파일들을 import 하여 사용하고 있는게 더 눈에 잘 띄기 시작했다. ㅤ 물론 이게 riverpod 방식으로 파일 구조를 짜려다보니, 앞서 올린 고민 이미지에서 그린 것 처럼 domain에서 data에서 작성한 파일을 필연적으로 impor..
너무나도 객체지향스러운 방식인 오버로딩을 다트 언어에서는 사용할 수가 없었다. 나는 코드를 가독성 넘치면서 깔끔하게 작성하는데에 있어서 오버라이딩, 오버로딩만큼이나 유용한 도구가 없다고 생각했는데, 요런게 제공이 잘 되지 않다보니 좀 불편함을 느끼게 되는 것 같다. ㅤ 아래가 내가 희망하던 코드의 방식이고 // 내가 짜고싶은 코드 List getEntityList({ DateTime bySelectedDate, }) { ... } List getEntityList({ String bySelectedUserId, }) { ... } // -> 이걸 사용하는 시점에는 list = getEntityList(bySelectedDate: DateTime); list = getEntityList(bySelected..
Data Layer 쪽의 리펙토링을 진행하면서, 내가 데이터 계층의 Repository Impl 클래스를 파이어베이스에 의존적이게 코드를 작성하고 있다는 걸 깨달았다. 클린 아키텍처의 의의를 ‘쉽게 갈아끼울 수 있는 백엔드와 프론트엔드’ 라고 생각하고 적용하려고 노력하고 있기 때문에, 범용 클래스를 무조건 “특정 서비스에 의존적이지 않은 형태”로 작성해야 한다고 생각한다. 이에 요걸 분리하기 위해서 여러가지 고민을 했고, 이걸 글로 남겨두려고 한다! ㅤ 현재 계층 구조와 설계한 사용 모델들을 간략하게 써보면 아래와 같다. Presentation Layer에서는 뷰 계층의 model을 사용한다. Domain Layer에서는 Entity를 사용한다. Data Layer에서는 데이터 계층의 model을 사용한..
파이어베이스에서 데이터를 받아올 때 시간과 날짜를 나타내는 자료형이 Timestamp였고, 플러터에서는 Datetime을 사용하고 있었다. 나는 Timestamp가 flutter(dart)의 내부 클래스이고, datetime과 timestamp가 같은 타입이라고 생각했는데, Timestamp는 Firestore 프레임워크에 포함된 타입이며 datetime으로 사용하기 위해서는 명시적으로 형변환 과정을 거쳐야 하는 것을 확인했다. ㅤ 검색해서 찾다보니 누군가는 Timestamp가 더 세밀한 초 (millisecond)를 표현할 수 있는 자료형이라고 했는데, 파이어베이스에서는 초 단위까지만 입력이 가능하고, DateTime 클래스의 프로퍼티에 microsecond 단위의 데이터를 넣을 수 있는 것으로 보아서..