18일차 과제 - rlatkddbs99/Flutter GitHub Wiki

비밀듣는 고양이

maid.dart

import 'package:flutter/material.dart';
import 'package:secret/pages/main_page.dart';
import 'package:secret_cat_sdk/api/api.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MainPage(),
      theme: ThemeData(fontFamily: "Neo"),
    );
  }
}

캡처5

main_page.dart

//ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:secret/pages/author_page.dart';
import 'package:secret/pages/secret_page.dart';
import 'package:secret/pages/upload_page.dart';

class MainPage extends StatelessWidget {
  const MainPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.orangeAccent,
        body: Center(
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CircleAvatar(
                  radius: 56,
                  backgroundColor: Colors.white38,
                  backgroundImage: AssetImage('assets/images/character.jpg'),
                ),
                SizedBox(
                  height: 8,
                ),
                Text(
                  "비밀듣는 고양이",
                  style: TextStyle(color: Colors.white, fontSize: 34),
                ),
                SizedBox(
                  height: 36,
                ),
                ListTile(
                  tileColor: Colors.white,
                  title: Text("비밀보기"),
                  subtitle: Text("놀러가기"),
                  onTap: () {
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (context) => SecretPage(),
                        ));
                  },
                  trailing: CircleAvatar(
                    backgroundColor: Colors.white38,
                    backgroundImage: AssetImage('assets/images/character.jpg'),
                  ),
                ),
                SizedBox(
                  height: 8,
                ),
                ListTile(
                  tileColor: Colors.white,
                  title: Text("작성자 보기"),
                  subtitle: Text("놀러가기"),
                  onTap: () {
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (context) => AuthorPage(),
                        ));
                  },
                  trailing: CircleAvatar(
                    backgroundColor: Colors.white38,
                    backgroundImage: AssetImage('assets/images/character.jpg'),
                  ),
                ),
                SizedBox(
                  height: 8,
                ),
                ListTile(
                  tileColor: Colors.white,
                  title: Text("비밀 남기기"),
                  subtitle: Text("놀러가기"),
                  onTap: () {
                    Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (context) => UploadPage(),
                        ));
                  },
                  trailing: CircleAvatar(
                    backgroundColor: Colors.white38,
                    backgroundImage: AssetImage('assets/images/character.jpg'),
                  ),
                ),
              ],
            ),
          ),
        ));
  }
}

캡처6

secret_page.dart

import 'package:animate_do/animate_do.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:secret_cat_sdk/api/api.dart';
import 'package:secret_cat_sdk/secret_cat_sdk.dart';

var backgroundImg =
    "https://images.unsplash.com/photo-1574144611937-0df059b5ef3e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MjR8fGNhdHxlbnwwfHwwfHw%3D&auto=format&fit=crop&w=500&q=60";

class SecretPage extends StatelessWidget {
  const SecretPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        extendBodyBehindAppBar: true, //body가 앱바 영역까지 차지
        appBar: AppBar(
          centerTitle: false,
          title: Text("뒤로가기"),
          backgroundColor: Colors.transparent,
          elevation: 0,
        ),
        body: Container(
          alignment: Alignment.center, //container가 크기 전부 차지
          decoration: BoxDecoration(
            image: DecorationImage(
                image: NetworkImage(backgroundImg),
                fit: BoxFit.cover,
                colorFilter:
                    ColorFilter.mode(Colors.black54, BlendMode.darken)),
          ),
          child: FutureBuilder(
              future: SecretCatApi.fetchSecrets(),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  // var reversedList = snapshot.data!.reversed.toList();  //제일 나중에 들어간 비밀이 제일 첫번쨰로, 근데 왜 난 이거 없이 되는거지. 중요 결과값 이터러블이라 리스트로 바꿈
                  return PageView.builder(
                      itemCount: snapshot.data
                          ?.length, //snapshot 데이터 수만큼 페이지뷰 생성, null일수도 있어서 ?붙여줘야돼
                      itemBuilder: (context, index) {
                        return FadeInRight(
                          delay: Duration(microseconds: 2000),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.center,
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              CircleAvatar(
                                radius: 56,
                                backgroundColor: Colors.white38,
                                backgroundImage:
                                    AssetImage('assets/images/character.jpg'),
                              ),
                              SizedBox(
                                height: 24,
                              ),
                              Text(
                                snapshot.data![index]
                                    .secret, //인덱스로 비밀에 한개한개 접근, 무조건 데이터 있어라고 알려주려고 !붙여, revese했으면 reversedList[index].author?.username??"익명",이렇게 바꿔
                                textAlign: TextAlign.center,
                                style: TextStyle(
                                    color: Colors.white, fontSize: 24),
                              ),
                              SizedBox(
                                height: 8,
                              ),
                              Text(
                                snapshot.data![index].author?.username ??
                                    "익명", //작성자가 null일수도 있어 null일 때 익명이라고 표현
                                textAlign: TextAlign.center,
                                style: TextStyle(
                                    color: Colors.white, fontSize: 18),
                              ),
                            ],
                          ),
                        );
                      });
                }
                return CircularProgressIndicator();
              }),
        ));
  }
}

캡처7

Author_page.dart

import 'package:animate_do/animate_do.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:secret_cat_sdk/secret_cat_sdk.dart';

var backgroundImg =
    "https://images.unsplash.com/photo-1574144611937-0df059b5ef3e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MjR8fGNhdHxlbnwwfHwwfHw%3D&auto=format&fit=crop&w=500&q=60";

class AuthorPage extends StatelessWidget {
  const AuthorPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        extendBodyBehindAppBar: true, //body가 앱바 영역까지 차지
        appBar: AppBar(
          centerTitle: false,
          title: Text("뒤로가기"),
          backgroundColor: Colors.transparent,
          elevation: 0,
        ),
        body: Container(
          alignment: Alignment.center, //container가 크기 전부 차지
          decoration: BoxDecoration(
            image: DecorationImage(
                image: NetworkImage(backgroundImg),
                fit: BoxFit.cover,
                colorFilter:
                    ColorFilter.mode(Colors.black54, BlendMode.darken)),
          ),
          child: FutureBuilder(
              future: SecretCatApi.fetchAuthors(),
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.done) {
                  return GridView.builder(
                      itemCount: snapshot.data?.length,
                      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                          crossAxisCount: 3),
                      itemBuilder: ((context, index) {
                        return ZoomIn(
                          delay: Duration(
                              milliseconds: 200 *
                                  index), //리스트에 있는 이름 들을 한명한명 따로 에니메이션 적용하려면
                          child: Column(
                            children: [
                              CircleAvatar(
                                radius: 48,
                                backgroundImage: NetworkImage(snapshot
                                    .data![index]
                                    .avatar!), //프로바이더 형태, 3항 연산자 사용해서 null 체크 해줘야 하지만 무조건 있다고 확신하면 avatar 뒤에 !붙여
                              ),
                              SizedBox(
                                height: 8,
                              ),
                              Text(
                                snapshot.data![index].username,
                                style: TextStyle(color: Colors.white),
                              ),
                            ],
                          ),
                        );
                      }));
                }
                return SizedBox();
              }),
        ));
  }
}

캡처8 캡처9

Upload_page.dart

import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:secret_cat_sdk/api/api.dart';

var backgroundImg =
    "https://images.unsplash.com/photo-1574144611937-0df059b5ef3e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MjR8fGNhdHxlbnwwfHwwfHw%3D&auto=format&fit=crop&w=500&q=60";

class UploadPage extends StatelessWidget {
  const UploadPage({super.key});

  @override
  Widget build(BuildContext context) {
    var controller = TextEditingController();
    return Scaffold(
      extendBodyBehindAppBar: true, //body가 앱바 영역까지 차지
      appBar: AppBar(
        centerTitle: false,
        title: Text("뒤로가기"),
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: Container(
        alignment: Alignment.center, //container가 크기 전부 차지
        decoration: BoxDecoration(
          image: DecorationImage(
              image: NetworkImage(backgroundImg),
              fit: BoxFit.cover,
              colorFilter: ColorFilter.mode(Colors.black54, BlendMode.darken)),
        ),
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment:
                CrossAxisAlignment.stretch, //column 안에 있는 모든 위젯이 모든 영역을 차지
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              TextField(
                controller: controller,
                minLines: 7, //7줄 이상
                maxLines: 8,
                decoration:
                    InputDecoration(filled: true, fillColor: Colors.white24),
              ),
              ElevatedButton(
                  onPressed: () async {
                    if (controller.text != "") {
                      //빈 텍스트가 아니라면 추가
                      var secret = await SecretCatApi.addSecret(controller
                          .text); //TextField에 입력한 텍스트를 함수를 이용해서 비밀 추가하기
                      if (secret != null) {
                        Navigator.pop(context); //잘 올려지면 뒤로가기
                        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                            content: Text("비밀유지성공! ${secret.secret}")));
                      }
                    }
                  },
                  child: Text("업로드 하기")),
            ],
          ),
        ),
      ),
    );
  }
}
⚠️ **GitHub.com Fallback** ⚠️