본문 바로가기
  • 인공지능
  • 블록체인
  • 정보보안
코딩 알로하 :: two/하이브리드앱

패스트캠퍼스 챌린지 29일차

by nathan03 2021. 11. 29.
반응형

# 강의 제목 : 누적다운로드 120만+ 1인 개발자와 함께하는 앱 개발 입문 Online

# 강의 목표 : 기초부터 운영까지 앱 개발의 전체 프로세스를 이해한다. 
                  내 이름으로 된 앱을 최대 10개까지 만들어 출시할 수 있다. 
                  앱 개발자로 성장할 수 있는 초석을 다진다. 
                  반응 얻는 앱의 특징과 노하우를 알아간다. 
                  향후 강의 없이도 나만의 앱을 개발할수 있는 실력을 가진다. 

# 강의 요약 : 프로그램 설치부터 기본 문법, 광고 다는 법, 클론코딩을 진행하며 필수 지식을 학습한다. 
                 총 10개의 다른 주제로 실제 사용화 가능한 수준의 앱을 만들어본다.
                 나의 앱을 세상에 선보이기 위한 개발자 등록 및 배포를 진행한다. 
                 강사님의 리뷰/클레임 대응사례 등 앱 성공 포인트를 참고해 1인 개발자로서의 입지를 다진다. 

 # 강의 목차 : Flutter 실전 앱 제작
                    - 앱 기능 및 디자인 설계 및 초기 구조 만들기 (눈바디앱)
                    - 식단 기록 페이지 
                    - 눈바디 운동 기록 페이지 
                    - 달력 기록 페이지
                    - 달력 기록 페이지 2
                    - 통계 갤러리 알림 설정하기 - 29일차
                    - 다크모드 지원하기 - 29일차 
                         

# 강의 화면 : 

 

# 강의 내용 : 통계 갤러리 알림 설정하기 및 다크모드 지원하기 

1. 통계 페이지 만들기 
    - 이전 기록을 모두 확인 하기

# main.dart 

 void getAllHistories() async {
    todayFood = await dbHelper.queryAllFood();
    todayWorkout = await dbHelper.queryAllWorkout();
    todayEyeBody = await dbHelper.queryAllEyeBody();
    setState(() {

    });
  }
@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
      ),
      body: getPage(),
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        items: [
          BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: "오늘"
          ),
          BottomNavigationBarItem(
              icon: Icon(Icons.calendar_today),
              label: "기록"
          ),
          BottomNavigationBarItem(
              icon: Icon(Icons.bar_chart),
              label: "통계"
          ),
          BottomNavigationBarItem(
              icon: Icon(Icons.photo_album_outlined),
              label: "갤러리"
          ),
        ],
        currentIndex: currentIndex,
        onTap: (idx){
          setState(() {
            currentIndex = idx;
            if(currentIndex == 0 || currentIndex == 1){
              time = DateTime.now();
              getHistories();
            }else if(currentIndex == 2 || currentIndex == 3){
              getAllHistories();
            }
          });
        },
      ),
      floatingActionButton: [2, 3].contains(currentIndex) ? Container() : FloatingActionButton(
        onPressed: (){
          showModalBottomSheet(
              context: context,
              backgroundColor: Colors.white,
              builder: (ctx){
                return SizedBox(
                  height: 200,
                  child: Column(
                    children: [
                      TextButton(child: Text("식단"),
                        onPressed: () async {
                          await Navigator.of(context).push(
                              MaterialPageRoute(builder: (ctx) => FoodAddPage(
                                food: Food(
                                    date: Utils.getFormatTime(time),
                                    kcal: 0,
                                    memo: "",
                                    type: 0,
                                    image: ""
                                ),
                              ))
                          );
                          getHistories();
                        },),
                      TextButton(child: Text("운동"),
                        onPressed: () async {
                          await Navigator.of(context).push(
                              MaterialPageRoute(builder: (ctx) => WorkoutAddPage(
                                workout: Workout(
                                    date: Utils.getFormatTime(time),
                                    time: 0,
                                    memo: "",
                                    name: "",
                                    image: ""
                                ),
                              ))
                          );
                          getHistories();

                        },),
                      TextButton(child: Text("눈바디"),
                        onPressed: () async {
                          await Navigator.of(context).push(
                              MaterialPageRoute(builder: (ctx) => EyeBodyAddPage(
                                eyeBody: EyeBody(
                                    date: Utils.getFormatTime(time),
                                    weight: 0,
                                    image: ""
                                ),
                              ))
                          );
                          getHistories();
                        },),
                    ],
                  ),
                );
              }
          );
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }



2. 총기록 식단수, 운동수, 눈바디수 표시하기 
# main.dart

  Widget getChartPage(){
    return Container(
      child: Column(children: [
        getMainPage(),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            Text("총 기록 식단 수\n${todayFood.length}"),
            Text("총 기록 운동 수\n${todayWorkout.length}"),
            Text("총 기록 눈바디 수\n${todayEyeBody.length}"),
          ],
        )
      ]),
    );
  }

3. 갤러리 페이지에서 상세 확인하기 

Widget getGalleryPage(){
    return Container(
      child: GridView.count(
        crossAxisCount: 3,
        childAspectRatio: 1,
        children: List.generate(
            todayEyeBody.length, (idx){
          return EyeBodyCard(eyeBody: todayEyeBody[idx]);
        }
        ),
      ),
    );
  }

4. 알림 구현하기
pubspec.yaml -> flutter_local_notifications: ^4.0.1+2 추가하기 

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.0
  sqflite: ^1.3.2+4
  multi_image_picker: ^4.7.12
  table_calendar: ^2.3.3
  flutter_local_notifications: ^4.0.1+2

# main.dart 

import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;

FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;

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

  runZonedGuarded(() async {
    runApp(MyApp());
  }, (error, stackTrace){
    FirebaseCrashlytics.instance.recordError(error, stackTrace);
  });

  tz.initializeTimeZones();

  const AndroidNotificationChannel androidNotificationChannel = AndroidNotificationChannel("fastcampus", "eyebody", "eyebody notification");
  flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

  await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(
      androidNotificationChannel);
}

5. notification 초기화 

 Future<bool> initNotification() async {
    if(flutterLocalNotificationsPlugin == null){
      flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
    }

    var initSettingAndroid = AndroidInitializationSettings("app_icon");
    var initiOS = IOSInitializationSettings();

    var initSetting = InitializationSettings(
        android: initSettingAndroid, iOS: initiOS
    );

    await flutterLocalNotificationsPlugin.initialize(initSetting,
      onSelectNotification: (payload) async {

      }
    );

    setScheduling();
    return true;

  }

6. 스케줄링 구현하기 

void setScheduling() async{
    var android = AndroidNotificationDetails(
        "fastcampus", "eyebody", "eyebody notification",
        importance: Importance.max,
        priority: Priority.max);
    var ios = IOSNotificationDetails();

    NotificationDetails detail = NotificationDetails(
        iOS: ios,
        android: android
    );

    flutterLocalNotificationsPlugin.zonedSchedule(
        0, "오늘 다이어트를 기록해주세요!",
        "앱에서 기록을 알려주세요!!",
        tz.TZDateTime.from(DateTime.now().add(Duration(seconds: 10)), tz.local),
        detail,
        androidAllowWhileIdle: true,
        uiLocalNotificationDateInterpretation: UILocalNotificationDateInterpretation.absoluteTime,
        payload: "eyebody",
        matchDateTimeComponents: DateTimeComponents.time
    );
  }

7. UI 다크모드 하기 
- Scaffold의 background color 를 Colors.black87 등
- IOS 다크모드 칼러 확인

https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/dark-mode
               

 

Dark Mode - Visual Design - iOS - Human Interface Guidelines - Apple Developer

Dark Mode In iOS 13.0 and later, people can choose to adopt a dark system-wide appearance called Dark Mode. In Dark Mode, the system uses a darker color palette for all screens, views, menus, and controls, and it uses more vibrancy to make foreground conte

developer.apple.com

 

class WorkoutCard extends StatelessWidget {
  final Workout workout;
  WorkoutCard({Key key, this.workout}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return Container(
      margin: EdgeInsets.all(8),
      child: ClipRRect(
        child: Stack(
          children: [
            Positioned.fill(
              child: AssetThumb(asset: Asset(workout.image, "food.png", 0, 0), width: 300, height: 300),
            ),
            Positioned.fill(
              child: Container(color: Colors.black38),
            ),
            Container(
              alignment: Alignment.center,
              child: Text("${workout.name}", style: TextStyle(color: Colors.white),),
            )
          ],
        ),
        borderRadius: BorderRadius.circular(8),
      ),
    );
  }
}


# 교육 소감

# 본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

https://bit.ly/3FVdhDa

 

수강료 100% 환급 챌린지 | 패스트캠퍼스

딱 5일간 진행되는 환급챌린지로 수강료 100% 환급받으세요! 더 늦기전에 자기계발 막차 탑승!

fastcampus.co.kr

 

반응형

댓글