묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
GoRoute List 위치 질문입니다.
List<GoRoute> 를 go_router.dart가 아닌 auth_provider.dart에 넣은 이유가 있을까요?작동은 잘 되지만 코드가 헷갈릴 때가 있어 질문드립니다.라우터 관련 코드들은 go_router에 넣으면 가독성이 더 편해질 것 같은데 auth_provider에 넣은 이유가 있을까요??
-
해결됨[Bloc 응용] 실전 앱 만들기 (책 리뷰 앱) : SNS 로그인, Firebase 적용, Bloc 상태 관리, GoRouter
플러터 바탕화면 빠진후 앱 진행시
안녕하세요 . 섹션7의 검색 라우터를 진행하다가 우연히 바탕화면에 들어갔다가 앱마크를 재생버튼이 아닌앱 마크를 클릭을 했더니 splash 화면에서 로딩중으로만 계속 되어있고print를 찍었더니 아예 App()에 있는 Gorouter 자체를 타지를 않는 현상이 생기고 있습니다.혹시 바탕화면 갔다가 다시 홈페이지 화면으로 들어가려고 하는데방법이 있을까 해서 글을 작성드렸습니다. 감사합니다 ㅠㅠ
-
미해결
플러터 로컬 푸시 아이콘 질문있습니다.
import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:permission_handler/permission_handler.dart'; class FlutterLocalNotification { FlutterLocalNotification._(); static FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); static init() async { AndroidInitializationSettings androidInitializationSettings = const AndroidInitializationSettings('mipmap/ic_launcher'); InitializationSettings initializationSettings = InitializationSettings( android: androidInitializationSettings); await flutterLocalNotificationsPlugin.initialize(initializationSettings); } static Future<void> showNotification() async { const AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails('channel id', 'channel name', channelDescription: 'channel description', importance: Importance.max, priority: Priority.max, showWhen: false); const NotificationDetails notificationDetails = NotificationDetails( android: androidNotificationDetails, ); await flutterLocalNotificationsPlugin.show( 0, 'test title', 'test body', notificationDetails); //await flutterLocalNotificationsPlugin.cancel(0); 아이디가 0인 알람 삭제 } static Future<PermissionStatus> requestNotificationPermissions() async { final status = await Permission.notification.request(); return status; } } 다른 사람들 보면 아이콘도 같이 나오는데 저는 아이콘이 나오지 않아서 이렇게 질문드려요 어디가 이상한지 모르겠습니다.
-
해결됨[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
캘린더 생성 및 수정 관련 기능 관련 질문이 있습니다.
좋은 강의 올려주셔서 감사합니다!다름이 아니라 스케쥴 생성 및 수정하는 과정에서startTime이 endTime보다 클 경우 create나 update를 방지하는 기능을 추가 하고 싶습니다.클라이언트에서는(schedule_bottom_sheet.dart) onSavePressed에서 검증처리를 추가하면 될거 같은데,만약 서버에서도(drift_database.dart) 이중으로 create나 update가 되는걸 방지할려면은 createSchedule 및 updateScheduleById 내부 로직에서 검증 처리를 별도로 하면 되는지 궁금합니다.
-
미해결[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
구글 플러터 지도
안녕하세요 강의영상이나 책에는 아래 설치하는 내용은 없는것 같은데..안해도 무방한건지요?(아래 링크에는 yaml에 버전 추가하는 것은없던데 혹시 그걸로 대체되는 것인지..) 제가 google_maps_cluster_manager: ^3.0.0+1를 이용하려고 하는데 혹시 영향이 있을까봐 여쭙니다 :) https://developers.google.com/maps/flutter-package/config?hl=ko#android 이 작업을 간소화하려면 Android용 Secrets Gradle 플러그인을 사용하는 것이 좋습니다. 플러그인을 설치하여 API 키를 저장하는 방법은 다음과 같습니다.Android 스튜디오에서 프로젝트 수준 build.gradle 파일을 열고 다음 코드를 buildscript 아래 dependencies 요소에 추가합니다.plugins { // ... id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.1' apply false } 그런 다음 모듈 수준 build.gradle 파일을 열고 plugins 요소에 다음 코드를 추가합니다.id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' 파일을 저장하고 프로젝트를 Gradle과 동기화합니다.프로젝트 수준 디렉터리에서 local.properties를 열고 다음 코드를 추가합니다. YOUR_API_KEY를 API 키로 변경합니다. MAPS_API_KEY= YOUR_API_KEY
-
해결됨[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
ShellRoute 실행 결과가 이상합니다 ..
선생님이랑 코드 똑같이 쓰고 라우트 위치도 맞는데 NestedScreen 가보면 이렇게 나옵니다.아래는 더러울 수도 있지만 코드 전체 첨부합니다. class NestedScreen extends StatelessWidget { final Widget child; NestedScreen({super.key, required this.child}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(GoRouterState.of(context).matchedLocation), ), body: child, bottomNavigationBar: BottomNavigationBar( items: [ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'home', ), BottomNavigationBarItem( icon: Icon(Icons.person), label: 'person', ), BottomNavigationBarItem( icon: Icon(Icons.notifications), label: 'notifications', ), ], ), ); } } // router.dart ShellRoute( builder: (context, state, child) { return NestedScreen(child: child); }, routes: [ GoRoute( path: 'nested/a', builder: (_, state) => NestedChildScreen(routeName: '/nested/a'), ), GoRoute( path: 'nested/b', builder: (_, state) => NestedChildScreen(routeName: '/nested/b'), ), GoRoute( path: 'nested/c', builder: (_, state) => NestedChildScreen(routeName: '/nested/c'), ), ], ),
-
해결됨Flutter로 SNS 앱 만들기
접속중인 사용자의 정보 가져오기 강의 관련 질문
안녕하세요.강의 잘 듣고 있습니다.접속중인 사용자의 정보 가져오기 강의 관련 질문 있습니다.아래와 같이 영상과 같이 코딩했는데 빨간 줄이 지워지지 않습니다.Future<UserModel> 로 함수 정의를 했는데 빨간 줄이 지워지지 않습니다.무슨 문제인지 모르겠습니다. 바쁘신데 질문 읽어주셔서 감사합니다.
-
미해결[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
그냥 질문입니다.
데이터 관리를 SQLite와 Firebase와 무슨 차이점 인가요?제가 다른 강의를 보다가 넘어와서요.firebase가 익숙해서 드리는 질문입니다.또 어느 문제가 발생합니까?
-
해결됨Flutter로 SNS 앱 만들기
사용자 정보, 게시글 정보를 Model 클래스로 관리 강의 관련 질문
안녕하세요.강의 잘 듣고 있습니다.사용자 정보, 게시글 정보를 Model 클래스로 관리 강의 관련 질문 있습니다.그 전 강의인 firestore에 게시글 정보 저장 강의 까지는 firestore database에 정상적으로 data가 올라갔습니다.하지만, 사용자 정보, 게시글정보를 Model 클래스로 관리 강의에 따라 코드 작성 후firestore database에 data가 올라가지 않습니다.(storage는 잘 작동합니다.)//feed_model.dart // ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:convert'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:collection/collection.dart'; import 'package:sns_clonecode/models/urser_model.dart'; class FeedModel { final String uid; final String feedId; final String desc; final List<String> imageUrls; final List<String> likes; final int commentCount; final int likeCount; final Timestamp creatAt; final UserModel writer; const FeedModel({ required this.uid, required this.feedId, required this.desc, required this.imageUrls, required this.likes, required this.commentCount, required this.likeCount, required this.creatAt, required this.writer, }); Map<String, dynamic> toMap({ required DocumentReference<Map<String, dynamic>> userDocRef, }) { return { 'uid': this.uid, 'feedId': this.feedId, 'desc': this.desc, 'imageUrls': this.imageUrls, 'likes': this.likes, 'commentCount': this.commentCount, 'likeCount': this.likeCount, 'creatAt': this.creatAt, 'writer': userDocRef, }; } factory FeedModel.fromMap(Map<String, dynamic> map) { return FeedModel( uid: map['uid'], feedId: map['feedId'], desc: map['desc'], imageUrls: List<String>.from((map['imageUrls'])), likes: List<String>.from((map['likes'])), commentCount: map['commentCount'], likeCount: map['likeCount'], creatAt: map['creatAt'], writer: map['writer'], ); } } //user_model.dart // ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:convert'; class UserModel { final String uid; final String name; final String email; final String? profileImage; final int feedCount; final List<String> followers; final List<String> following; final List<String> likes; const UserModel({ required this.uid, required this.name, required this.email, required this.profileImage, required this.feedCount, required this.followers, required this.following, required this.likes, }); factory UserModel.init() { return UserModel( uid: '', name: '', email: '', profileImage: null, feedCount: 0, followers: [], following: [], likes: [], ); } //usermodle 이 가지고 있는 filed 변수로 가지고 있는 데이터들을 가지고 map 형태 데이터를 만들어 준다. Map<String, dynamic> toMap() { return { 'uid': this.uid, 'name': this.name, 'email': this.email, 'profileImage': this.profileImage, 'feedCount': this.feedCount, 'followers': this.followers, 'following': this.following, 'likes': this.likes, }; } //map 형태 데이터를 인자값을 전달 받아 usermolde 객체를 만들어 준다. factory UserModel.fromMap(Map<String, dynamic> map) { return UserModel( uid: map['uid'], name: map['name'], email: map['email'], profileImage: map['profileImage'], feedCount: map['feedCount'], followers: List<String>.from(map['followers']), following: List<String>.from(map['following']), likes: List<String>.from(map['likes']), ); } } //feed_repository.dart import 'dart:io'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:sns_clonecode/models/feed_model.dart'; import 'package:sns_clonecode/models/urser_model.dart'; import 'package:sns_clonecode/utils/logger.dart'; import 'package:uuid/uuid.dart'; class FeedRepository { final FirebaseStorage firebaseStorage; final FirebaseFirestore firebaseFirestore; const FeedRepository({ required this.firebaseFirestore, required this.firebaseStorage, }); Future<void> uploadFeed({ required List<String> files, required String desc, required String uid, //feeds 컬렉션에 저장 //피드 각각이 문서 //이미지는 storage에 직접 저장하고 firestore에 접근할 수 있는 url 문자열로 받을 것이다. //좋아요 수 //이 게시글에 달린 댓글의 수 //게시글을 작성한 날짜 //feeds에서 user의 정보를 바로 가져올 수 있게 reference 타입의 데이터를 저장한다. }) async { //파이어스토어에 데이터 저장하기위해서 //문서 아이디는 겹치지 않는 고유한 값으로 만들어야 한다. //a-z 알파벳 //0~9 숫자 //이 두가지를 조합해서 32글자의 고유한 값을 만들어 준다. //32글자에 - 4개씩 들어가서 36글자가 된다. //고유한 값을 만드는 방법 여러가지 version1 .... //우리는 version1을 사용 (현재 시간을 기준으로 random값을 만들어 준다.) String feedId = Uuid().v1(); //firestore 문서 참조 DocumentReference<Map<String, dynamic>> feedDocRef = firebaseFirestore.collection('feeds').doc(feedId); DocumentReference<Map<String, dynamic>> userDocRef = firebaseFirestore.collection('users').doc(uid); //storage 참조 Reference ref = firebaseStorage.ref().child('feeds').child(feedId); List<String> imageUrls = await Future.wait(files.map((e) async { //문자열 e는 이미지 파일에 접근할 수 있는 경로 String imageId = Uuid().v1(); TaskSnapshot taskSnapshot = await ref.child(imageId).putFile(File(e)); return await taskSnapshot.ref.getDownloadURL(); }).toList()); DocumentSnapshot<Map<String, dynamic>> userSnapshot = await userDocRef.get(); UserModel userModel = UserModel.fromMap(userSnapshot.data()!); FeedModel feedModel = FeedModel.fromMap({ 'uid': uid, 'feedId': feedId, 'desc': desc, 'imageUrls': imageUrls, 'likes': [], 'likeCount': 0, 'commentCount': 0, 'createAt': Timestamp.now(), 'writer': userModel, }); await feedDocRef.set(feedModel.toMap(userDocRef: userDocRef)); // await feedDocRef.set({ // 'uid': uid, // 'feedId': feedId, // 'desc': desc, // 'imageUrls': imageUrls, // 'likes': [], // 'commentCount': 0, // 'likeCount': 0, // 'creatAt': Timestamp.now(), // 'writer': userDocRef, // }); await userDocRef.update({ 'feedCount': FieldValue.increment(1), }); } } 바쁘실 텐데 질문 읽어주셔서 감사합니다.
-
미해결[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
위젯과 클래스
Boxdecoration()은 위젯이라고 볼 수 없는건가요? 볼 수 있는거 아닌가요?제가 이해하기로는 위젯과 위젯이 아닌 클래스의 차이로는위젯은 컨스트럭터 자체로 역할을 할 수 있고 위젯이 아닌 클래스는 컨스트럭터 자로 역할을 할 수는 없고, 그 컨스트럭터로 인스턴스를 만들고 그 인스턴스로 메서드나 멤버변수 이용라는걸로 이해하고 있습니다. 위 내용에 따르면 Boxdecoration()도 위젯 아닌가요?위젯과 위젯이 아닌 클래스를 나누는 명확한 기준이 있나오?
-
미해결[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
riverpod 상태관리시에 궁금한점 질문드립니다.
안녕하세요 코팩님.상품검색 페이지를 작업했습니다.riverpod으로 상태관리를 하며 필터(검색조건)을 provider로 구현하였습니다.필터들은 stateProvider로 하였고검색데이터 list는 StateNotifierProvider(필터값들 watch중)로 선언하였습니다.기본적으로 필터가 변경될때 자동으로 재검색이 되고 있는데요. 검색결과 페이지에서 새로운 검색어를 넣고 다시 검색할 때 이슈가 있습니다.(pushReplacementNamed로 현재페이지를 다시 호출)사정상 검색어는 provider로 하지 않고 파라미터로 받고 있습니다. 필터프로바이더들을 초기화 하지 않으면 새로운검색결과에 조건이 또 타게되서 필터들을 초기화 해주고 싶은데요.필터를 초기화해주면 기존 리스트가 자동으로 watch중이라 재검색이 먼저 실행되어버립니다.invalidate도 마찬가지구요. 어쩔수없이 changeNotifierProvider를 써서 notifyListeners를 호출하지 않고 값을 변경하는 함수를 따로 만들어서 그걸 호출 해서 값을 초기화하고 pushReplacementNamed로 현재페이지를 검색어만 바꿔서 재호출 하는걸로 처리하고 넘어갔습니다. 이럴땐 어떻게 처리해야 할까요?기본적인 설계를 잘못한 건지 모르겠습니다 ㅠㅠ조언 부탁드립니다. ps. autoDispose를 걸어놔도 다음 페이지에서 해당 프로바이더를 사용하면 dispose가 되지 않고 상태값도 초기화없이 유지되는게 맞나요? 테스트해 보았는데 그렇게 처리되는 것처럼 보여서요. 긴글 읽어주셔사 감사합니다.
-
미해결[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
안스에 location custom
지도 강의에 features-custom location 가서 경도 위도 바꾸는 게 있는데안스에서는 이런걸 찾을 수 가 없네요.아래와 같이 이유를 얘기하는데 저는 해당되는게 하나도없고 File > Settings에서Appearance & Behavior > System Settings 가봐도 location 이 없네요ㅜ 안드로이드 스튜디오의 버전이 너무 낮습니다.안드로이드 스튜디오를 설치할 때 Location 옵션이 비활성화되어 있습니다.안드로이드 스튜디오의 위치 서비스가 비활성화되어 있습니다.안드로이드 스튜디오의 설정에서 Location 옵션이 숨겨져 있습니다.
-
미해결[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
탭 간 상태 유지 관련 하여 문의 드립니다.
홈 리스트 화면 중간 정도 보다가 음식 탭으로 이동 해서 리스트 스크롤 후에 다시 홈 화면으로 탭 하면 홈 리스트가 처음 부터 보여 집니다. 음식 탭으로 이동 해도 처음부터 보여지는데 상태 유지 할 수 있는 방법에는 어떤게 있는지 궁금 해서 문의 드립니다. 현재 Go router 강의 중간 정도 진행했습니다.감사합니다.
-
미해결[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
NavigatorObserver
[에러코드]Error (Xcode): ../../../.pub-cache/hosted/pub.dev/go_router-4.5.1/lib/src/router.dart:38:44: Error: The class 'NavigatorObserver' can't be used as a mixin because it isn't a mixin class nor a mixin.Could not build the application for the simulator.Error launching application on iPhone 15 Pro.[강의]섹션 15 GoRouter 프로젝트에 적용하기 Authentication 마무리하기 수강 완료 후 위와 같은 에러가 발생하는데... 어떻게 하면 해결 가능할지... 문의드립니다.
-
미해결[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
파이어베이스 설정중 안드로이드스튜디오 프로젝트 에러
정말 죄송하지만파이어베이스 관련에러인데요코팩 책을 보면서 파이어베이스 설정을 하다가Flutterfire configure 부터 오피셜 파어베이스가 필요하다는 에러만 뜨더라고요구글링 해보니 적용하려는 안스 프로젝트의 폴더에 파베 파일을 넣어보라길래(기존 작업중이던 프로젝트)그대로 했더니파베도 설정 안되고멀쩡하던 안스 프로젝트까지 아래와 같이 에러가 났습니다.* What went wrong: A problem occurred configuring project ':cloud_firestore'. > defaultConfig contains custom BuildConfig fields, but the feature is disabled. To enable the feature, add the following to your module-level build.gradle: `android.buildFeatures.buildConfig true` 일단 해당 파베를 지웠다가 아예 다른 d드라이브에 다시 깔아봤지만 동일하고..그래들 프로퍼티 파일에 아래를 추가도 했고요android.buildFeatures.buildConfig=true어떻게도 위 에러가 없어지질 않네요ㅜ위 에러메시지는 어떤 부분을 봐야하는지 방향성만이라도 알려주시면 감사하겠습니다.
-
미해결[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
강의 내용으로 블로그를 작성해도 될까요?
강의를 보고 배운내용을 오래 기억하기 위해 인용하여 블로그를 작성해도 될까요? 핵심이라고 생각되는 소스코드를 복사하거나가끔 이론설명 하실때 사용하시는 ppt 페이지(그림) 일부분 이런걸 복사한 뒤, 저의 생각과 함께 글을 작성해보려고 하는데 가능할까요?medium 블로그를 통해 출처와 같이 작성할 것 같습니다.
-
미해결[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
flutter doctor cocoapods 설치 오류
intel mac 유저입니다.강의에서 말씀하신대로 homebrew 통해서 cocoapods 설치 한 후 flutter doctor 실행 하는데 계속 저런 화면이 뜨네요...해결해 보려고 sudo gem install cocoapods 실행하면이런 화면이 뜨구요...해결 방법 알려 주시면 감사하겠습니다....ㅠㅠㅠ
-
해결됨[2024 최신] [코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
자동 재생에 대해 궁금한 점이 있습니다.
좋은 강의 감사합니다.강의 내용을 듣다보니, 동영상을 실행하면 자동 재생 기능이 따로 없는걸로 보여서 공식 문서를 참조 한 뒤 아래와 같은 기능 한 줄을 추가 했습니다. initializeController() async { currentPosition = Duration(); videoPlayerController = VideoPlayerController.file( File(widget.video.path), ); await videoPlayerController!.initialize(); await videoPlayerController!.play(); // 자동 재생 시작 videoPlayerController!.addListener(() async { final currentPosition = videoPlayerController!.value.position; setState(() { this.currentPosition = currentPosition; }); }); setState(() {}); } 이런식으로 await videoPlayerController!.initialize();밑에 추가를 했는데, 테스트는 해보니 이상이 없어서 혹시 코드 내부 로직상으로도 문제가 없는지 궁금합니다.
-
미해결[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
리스너 dispose 질문입니다
5분 15초 쯤에 ScrollController 의 리스너 dispose하고ScrollController 도 dispose 하시는데 질문이 3가지 있습니다.둘 중 하나라도 dispose를 안 하면 어떻게 되는 건가요?RestaurantScreen, DetailScreen 에서는 dispose를 안 했는데 여기에서 한 이유가 있을까요?모든 리스너들은 다 dispose를 해줘야 하는지입니다.
-
해결됨[코드팩토리] [중급] Flutter 진짜 실전! 상태관리, 캐시관리, Code Generation, GoRouter, 인증로직 등 중수가 되기 위한 필수 스킬들!
아래 댓글에 답변 드립니다.
계속 질문드려 죄송합니다. 그리고 매번 답변 주셔서 진심으로 감사드립니다. 제가 위탁하여 가지고있는 2년 전 flutter와 firebase로 제작한 앱이 있습니다. 그런데 지금 제가 공부중이라 안드로이드 스튜디오로 열려고 하니 다양한 이유로 에뮬레이터에 구현이 안되더라고요, 일부 코드들은 지금은 안쓰는 것 같고, 코드 수정은 어찌어찌 제가 할 수 있을 것 같은데, 새플러터 프로젝트로 코드 복사하고, 야믈파일, 안드로이드, ios 일부 수정해야하는 파일을 복사해와도 실행이 안되는건 마찬가지였습니다. 이런때는 어떻게 해야할까요?; 해당 개발자에게 문의를 해봐도 안드로이드 환경설정은 어떻게 해줄 수가 없다고 하더라고요, 원본 파일에서 최대한 아무것도 바꾸지 않는게 좋다고 하는데, 열 수가 없습니다.