name27 / flutter

0 stars 0 forks source link

비밀 듣는 고양이 로그인 저장, dio 싱글톤 등 #109

Open name27 opened 1 year ago

name27 commented 1 year ago

image image

image image image image image image

main.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/auth_controller.dart';
import 'package:secret_cat_app/controller/login_controller.dart';
import 'package:secret_cat_app/controller/secret_controller.dart';
import 'package:secret_cat_app/controller/sign_up_controller.dart';
import 'package:secret_cat_app/controller/upload_controller.dart';
import 'package:secret_cat_app/controller/user_controler.dart';
import 'package:secret_cat_app/util/pages.dart';
import 'package:secret_cat_app/util/routes.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      theme: ThemeData(fontFamily: 'neo'),
      debugShowCheckedModeBanner: false,
      initialBinding: BindingsBuilder(() {
        Get.put(AuthController());
        Get.put(LoginController());
        Get.put(SignUpController());
        Get.lazyPut(() => SecretController(), fenix: true);
        Get.lazyPut(() => UploadController(), fenix: true);
        Get.lazyPut(() => UserController(), fenix: true);
      }),
      getPages: AppPages.pages,
      initialRoute: AppRoute.login,
    );
  }
}

login_page.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/login_controller.dart';
import 'package:secret_cat_app/util/routes.dart';
import 'package:secret_cat_app/view/widget/app_image.dart';
import 'package:secret_cat_app/view/widget/custom_text_field.dart';

class LoginPage extends GetView<LoginController> {
  const LoginPage({super.key});
  static String route = '/login';

  @override
  Widget build(BuildContext context) {
    return Container(
      color: const Color.fromARGB(255, 255, 240, 196),
      child: Scaffold(
        backgroundColor: Colors.transparent,
        body: Form(
          key: controller.formKey,
          child: Center(
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 30.0),
              child: SingleChildScrollView(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      '로그인',
                      style: TextStyle(
                          color: Colors.brown,
                          fontWeight: FontWeight.w600,
                          fontSize: 20),
                    ),
                    const SizedBox(
                      height: 15,
                    ),
                    const AppImage(),
                    CustomTextField(
                      controller: controller.idController,
                      textValidator: controller.idCheck,
                      textHint: 'ID',
                    ),
                    CustomTextField(
                      controller: controller.pwController,
                      textValidator: controller.pwCheck,
                      textHint: 'PW',
                    ),
                    Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        Obx(
                          () => Checkbox(
                            value: controller.isIdPw.value,
                            onChanged: (val){
                              controller.saveIdPw(val);
                            },
                          ),
                        ),
                        const Text('로그인 정보 저장'),
                      ],
                    ),
                    Center(
                        child: SizedBox(
                      width: Get.width * 0.9,
                      height: 50,
                      child: ElevatedButton(
                          style: ElevatedButton.styleFrom(
                            backgroundColor: Colors.white,
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(30.0),
                            ),
                          ),
                          onPressed: controller.login,
                          child: const Text(
                            '로그인',
                            style: TextStyle(
                                color: Colors.brown,
                                fontWeight: FontWeight.w600),
                          )),
                    )),
                    Center(
                      child: TextButton(
                        onPressed: () {
                          Get.toNamed(AppRoute.signup);
                        },
                        child: const Text(
                          '회원가입',
                          style: TextStyle(
                              color: Colors.brown, fontWeight: FontWeight.w500),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

sign_up_page.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/sign_up_controller.dart';
import 'package:secret_cat_app/view/widget/app_image.dart';
import 'package:secret_cat_app/view/widget/custom_text_field.dart';

class SignUpPage extends GetView<SignUpController> {
  const SignUpPage({super.key});
  static String route = '/signup';

  @override
  Widget build(BuildContext context) {
    return Container(
      color: const Color.fromARGB(255, 255, 240, 196),
      child: Scaffold(
        appBar: AppBar(
          foregroundColor: Colors.brown,
          backgroundColor: Colors.transparent,
          elevation: 0,
        ),
        backgroundColor: Colors.transparent,
        body: Center(
          child: Form(
            key: controller.formKey,
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 30.0),
              child: SingleChildScrollView(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      '회원가입',
                      style: TextStyle(
                          color: Colors.brown,
                          fontWeight: FontWeight.w600,
                          fontSize: 20),
                    ),
                    const AppImage(),
                    CustomTextField(
                        controller: controller.emailController,
                        textValidator: controller.emailCheck,
                        textHint: 'Email'),
                    CustomTextField(
                        controller: controller.pwController,
                        textValidator: controller.pwCheck,
                        textHint: 'PW'),
                    CustomTextField(
                        controller: controller.pwCheckController,
                        textValidator: controller.pwDoubleCheck,
                        textHint: 'PW 2'),
                    CustomTextField(
                        controller: controller.nameController, textHint: '닉네임'),
                    SizedBox(
                      height: Get.height * 0.07,
                    ),
                    Center(
                        child: SizedBox(
                      width: Get.width * 0.9,
                      height: 50,
                      child: ElevatedButton(
                          style: ElevatedButton.styleFrom(
                            backgroundColor: Colors.white,
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(30.0),
                            ),
                          ),
                          onPressed: () {
                            controller.start();
                          },
                          child: const Text(
                            '회원가입',
                            style: TextStyle(
                                color: Colors.brown,
                                fontWeight: FontWeight.w600),
                          )),
                    )),
                  ],
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

main_page.dart

import 'package:flutter/material.dart';
import 'package:secret_cat_app/util/routes.dart';
import 'package:secret_cat_app/view/widget/app_image.dart';
import 'package:secret_cat_app/view/widget/menu_tile.dart';

class MainPage extends StatelessWidget {
  const MainPage({super.key});
  static String route = '/main';

  @override
  Widget build(BuildContext context) {
    return Container(
        color: const Color.fromARGB(255, 255, 240, 196),
        child: Scaffold(
          backgroundColor: Colors.transparent,
          body: Center(
            child: SingleChildScrollView(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Text(
                      '비밀 듣는 고양이',
                      style: TextStyle(
                          color: Colors.brown,
                          fontWeight: FontWeight.w600,
                          fontSize: 25),
                    ),
                  ),
                  const AppImage(),
                  MenuTile(
                      title: '비밀보기',
                      subtitle: '오늘의 비밀을 확인하세요',
                      route: AppRoute.secret),
                  MenuTile(
                      title: '비밀만들기',
                      subtitle: '비밀을 만들어 보세요',
                      route: AppRoute.upload),
                  MenuTile(
                      title: '설정',
                      subtitle: '비밀 듣는 고양이',
                      route: AppRoute.setting),
                ],
              ),
            ),
          ),
        ));
  }
}

secret_page.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/secret_controller.dart';

class SecretPage extends GetView<SecretController> {
  const SecretPage({super.key});
  static String route = '/secret';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: Container(
        decoration: const BoxDecoration(
            color: Colors.black,
            image: DecorationImage(
                image: AssetImage('assets/images/backgroundImage.jpg'),
                fit: BoxFit.cover,
                opacity: 0.5)),
        child: Center(
          child: Obx(
            () => PageView.builder(
              itemCount: controller.secret?.length ?? 0,
              itemBuilder: (context, index) => Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    controller.secret![index].secret,
                    style: const TextStyle(
                        color: Colors.white,
                        fontWeight: FontWeight.bold,
                        fontSize: 18),
                    textAlign: TextAlign.center,
                  ),
                  const SizedBox(
                    height: 8,
                  ),
                  Text(
                    controller.secret![index].authorName != ''
                        ? controller.secret![index].authorName!
                        : '익명',
                    style: const TextStyle(color: Colors.white),
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

setting_page.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/auth_controller.dart';
import 'package:secret_cat_app/util/routes.dart';

class SettingPage extends GetView<AuthController> {
  const SettingPage({super.key});
  static String route = '/setting';

  @override
  Widget build(BuildContext context) {
    return Container(
      color: const Color.fromARGB(255, 255, 240, 196),
      child: Scaffold(
        backgroundColor: Colors.transparent,
        appBar: AppBar(
          foregroundColor: Colors.brown,
          backgroundColor: Colors.transparent,
          elevation: 0,
        ),
        body: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              children: [
                ElevatedButton(
                  style:
                      ElevatedButton.styleFrom(backgroundColor: Colors.white),
                  onPressed: () {},
                  child: ListTile(
                    title: Text(controller.profile!.username),
                    subtitle: Text('${controller.profile!.username}입니다'),
                    trailing: CircleAvatar(
                      backgroundColor: Colors.black12,
                      child: Text(
                        controller.profile!.username.substring(0, 1),
                        style: const TextStyle(color: Colors.black),
                      ),
                      //backgroundImage: NetworkImage(controller.profile.avatar),
                    ),
                  ),
                ),
                const SizedBox(
                  height: 10,
                ),
                ElevatedButton(
                  style:
                      ElevatedButton.styleFrom(backgroundColor: Colors.white),
                  onPressed: () {Get.toNamed(AppRoute.user);},
                  child: const ListTile(
                      title: Text('유저 목록 보기'),
                      subtitle: Text('유저 리스트 페이지 이동'),
                    ),
                ),
                ListTile(
                  title: const Text('로그아웃'),
                  subtitle: const Text('로그아웃하기'),
                  trailing: GestureDetector(
                      onTap: controller.logout,
                      child: const Icon(Icons.logout)),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

upload_page.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/upload_controller.dart';

class UploadPage extends GetView<UploadController> {
  const UploadPage({super.key});
  static String route = '/upload';

  @override
  Widget build(BuildContext context) {
    return Container(
      color: const Color.fromARGB(255, 255, 240, 196),
      child: Scaffold(
        backgroundColor: Colors.transparent,
        extendBodyBehindAppBar: true,
        appBar: AppBar(
          foregroundColor: Colors.brown,
          backgroundColor: Colors.transparent,
          elevation: 0,
        ),
        body: Center(
            child: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Image.asset(
                  'assets/images/kitty.png',
                  width: 80,
                  height: 80,
                ),
                SizedBox(
                    child: TextField(
                  controller: controller.inputController,
                  minLines: 7,
                  maxLines: 8,
                  decoration: const InputDecoration(
                      filled: true,
                      hintText: '비밀을 입력하세요',
                      hintStyle: TextStyle(color: Colors.black),
                      enabledBorder: OutlineInputBorder(
                          borderSide: BorderSide(width: 0.5))),
                )),
                Row(
                  children: [
                    Obx(
                      () => Checkbox(
                        value: controller.isName.value,
                        onChanged: controller.checkName,
                      ),
                    ),
                    const Text('내 이름 공유하기'),
                  ],
                ),
                ElevatedButton(
                    style:
                        ElevatedButton.styleFrom(backgroundColor: Colors.white),
                    onPressed: controller.startUpload,
                    child: const Text(
                      '비밀 공유',
                      style: TextStyle(color: Colors.black),
                    )),
              ],
            ),
          ),
        )),
      ),
    );
  }
}

users_page.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/user_controler.dart';

class UsersPage extends GetView<UserController> {
  const UsersPage({super.key});
  static String route = '/user';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
      ),
      body: Container(
        decoration: const BoxDecoration(
            color: Colors.black,
            image: DecorationImage(
                image: AssetImage('assets/images/backgroundImage.jpg'),
                fit: BoxFit.cover,
                opacity: 0.7)),
        child: Obx(
          () => ListView.builder(
            itemCount: controller.users?.length ?? 0,
            itemBuilder: (context, index) => Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(
                    controller.users![index].username,
                    style: const TextStyle(color: Colors.white),
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

app_image.dart

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(3.0),
      child: CircleAvatar(
        radius: 60,
        backgroundColor: Colors.white,
        child: Image.asset(
          'assets/images/kitty.png',
          width: 80,
          height: 80,
        ),
      ),
    );
  }
}

custom_text_field.dart

import 'package:flutter/material.dart';

class CustomTextField extends StatelessWidget {
  const CustomTextField(
      {super.key,
      required this.controller,
      this.textValidator,
      required this.textHint});
  final TextEditingController controller;
  final Function? textValidator;
  final String textHint;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 3.0),
      child: TextFormField(
        controller: controller,
        decoration: InputDecoration(
            enabledBorder: const OutlineInputBorder(
                borderSide: BorderSide(
              width: 0.2,
            )),
            hintText: textHint,
            filled: true,
            fillColor: Colors.white),
        validator: (val) {
          return textValidator != null ? textValidator!(val!) : null;
        },
      ),
    );
  }
}

menu_tile.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';

class MenuTile extends StatelessWidget {
  const MenuTile({super.key, required this.title, required this.subtitle, required this.route});
  final String title;
  final String subtitle;
  final String route;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical:8.0),
      child: SizedBox(
        width: Get.width * 0.8,
        child: ElevatedButton(
            style: ElevatedButton.styleFrom(backgroundColor: Colors.white),
            onPressed: () {
              Get.toNamed(route);
            },
            child:  ListTile(
              title: Text(title,
                  style: const TextStyle(
                      color: Colors.brown, fontWeight: FontWeight.w600)),
              subtitle: Text( subtitle),
              //trailing: Image.asset('ass'),
            )),
      ),
    );
  }
}

profile.dart

import 'dart:convert';

// ignore_for_file: public_member_api_docs, sort_constructors_first
class Profile {
  String id;
  String username;
  String? email;
  String? name;
  Profile({
    required this.id,
    required this.username,
    required this.email,
    required this.name,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'id': id,
      'username': username,
      'email': email,
      'name': name,
    };
  }

  factory Profile.fromMap(Map<String, dynamic> map) {
    return Profile(
      id: map['id'] as String,
      username: map['username'] as String,
      email: map['email'] != null ? map['email'] as String : null,
      name: map['name'] != null ? map['name'] as String : null,
    );
  }

  String toJson() => json.encode(toMap());

  factory Profile.fromJson(String source) =>
      Profile.fromMap(json.decode(source) as Map<String, dynamic>);
}

secret.dart

import 'dart:convert';

// ignore_for_file: public_member_api_docs, sort_constructors_first
class Secret {
  String? id;
  String secret;
  String? authorName;
  Secret({
    required this.id,
    required this.secret,
    required this.authorName,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'id': id,
      'secret': secret,
      'authorName': authorName,
    };
  }

  factory Secret.fromMap(Map<String, dynamic> map) {
    return Secret(
      id: map['id'] != null ? map['id'] as String : null,
      secret: map['secret'] as String,
      authorName:
          map['authorName'] != null ? map['authorName'] as String : null,
    );
  }

  String toJson() => json.encode(toMap());

  factory Secret.fromJson(String source) =>
      Secret.fromMap(json.decode(source) as Map<String, dynamic>);
}

user.dart

import 'dart:convert';

// ignore_for_file: public_member_api_docs, sort_constructors_first
class User {
  String id;
  String username;
  String? email;
  String? name;
  User({
    required this.id,
    required this.username,

    this.email,
    this.name,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'id': id,
      'username': username,
      'email': email,
      'name': name,
    };
  }

  factory User.fromMap(Map<String, dynamic> map) {
    return User(
      id: map['id'] as String,
      username: map['username'] as String,
      email: map['email'] != null ? map['email'] as String : null,
      name: map['name'] != null ? map['name'] as String : null,
    );
  }

  String toJson() => json.encode(toMap());

  factory User.fromJson(String source) => User.fromMap(json.decode(source) as Map<String, dynamic>);
}

api_routes.dart

class ApiRoutes {
  static String login =
      '/api/collections/users/auth-with-password';
  static String signUp =
      '/api/collections/users/records';
  static String secret =
      '/api/collections/secrets/records?sort=-created';
  static String upload =
      '/api/collections/secrets/records';
  static String user =
      '/api/collections/users/records?sort=-created';
  static String save = '/api/collections/users/auth-refresh';
}

custom_dio.dart

import 'package:dio/dio.dart';

class CustomDio {
  static final CustomDio _instance = CustomDio._internal();
  final Dio _dio = Dio();

  CustomDio._internal() {
    _dio.options.baseUrl = "http://52.79.115.43:8090"; // API 주소 설정
    // 기타 Dio 객체 설정
  }
  factory CustomDio() {
    return _instance;
  }

  Dio get dio => _dio;
}

pages.dart

import 'package:get/get.dart';
import 'package:secret_cat_app/util/routes.dart';
import 'package:secret_cat_app/view/pages/login_page.dart';
import 'package:secret_cat_app/view/pages/main_page.dart';
import 'package:secret_cat_app/view/pages/secret_page.dart';
import 'package:secret_cat_app/view/pages/setting_page.dart';
import 'package:secret_cat_app/view/pages/sign_up_page.dart';
import 'package:secret_cat_app/view/pages/upload_page.dart';
import 'package:secret_cat_app/view/pages/users_page.dart';

class AppPages{
  static final pages = [
    GetPage(name: AppRoute.main, page: ()=> const MainPage()),
    GetPage(name: AppRoute.signup, page: ()=> const SignUpPage()),
    GetPage(name: AppRoute.login, page: ()=> const LoginPage()),
    GetPage(name: AppRoute.secret, page: ()=> const SecretPage()),
    GetPage(name: AppRoute.setting, page: ()=> const SettingPage()),
    GetPage(name: AppRoute.upload, page: ()=> const UploadPage()),
    GetPage(name: AppRoute.user, page: ()=> const UsersPage())
  ];
}

routes.dart

import 'package:secret_cat_app/view/pages/login_page.dart';
import 'package:secret_cat_app/view/pages/main_page.dart';
import 'package:secret_cat_app/view/pages/secret_page.dart';
import 'package:secret_cat_app/view/pages/setting_page.dart';
import 'package:secret_cat_app/view/pages/sign_up_page.dart';
import 'package:secret_cat_app/view/pages/upload_page.dart';
import 'package:secret_cat_app/view/pages/users_page.dart';

class AppRoute{
  static final main = MainPage.route;
  static final signup = SignUpPage.route;
  static final login = LoginPage.route;
  static final upload = UploadPage.route;
  static final secret = SecretPage.route;
  static final setting = SettingPage.route;
  static final user = UsersPage.route;
}

auth_controller.dart

import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:dio/dio.dart';
import 'package:secret_cat_app/controller/login_controller.dart';
import 'package:secret_cat_app/controller/sign_up_controller.dart';
import 'package:secret_cat_app/model/profile.dart';
import 'package:secret_cat_app/util/api_routes.dart';
import 'package:secret_cat_app/util/custom_dio.dart';
import 'package:secret_cat_app/util/routes.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AuthController extends GetxController {
  final Rxn<Profile> _profile = Rxn<Profile>();
  SharedPreferences? prefs;
  final customDio = CustomDio();

  Profile? get profile => _profile.value;

  signUp(String email, String password, String passwordConfirm,
      String? username) async {
    try {
      var res = await customDio.dio.post(ApiRoutes.signUp,
          data: {
            'email': email,
            'password': password,
            'passwordConfirm': passwordConfirm,
            'username': username,
          });
      if (res.statusCode == 200) {
        var data = Map<String, dynamic>.from(res.data);
        _profile(Profile.fromMap(data));
      }
    } on DioError catch (e) {
      print(e.message);
    }
  }

  saveUser() async {
    prefs = await SharedPreferences.getInstance();
    try {
      var res = await customDio.dio.post(ApiRoutes.save,
          options: Options(headers: {
            'authorization':
                'Bearer ${prefs != null ? prefs!.getString('token') : null}'
          }));
      if (res.statusCode == 200) {
        var data = Map<String, dynamic>.from(res.data['record']);
        _profile(Profile.fromMap(data));
      }
    } on DioError catch (e) {
      print(e.message);
    }
  }

  login(String id, String pw) async {
    try {
      var res = await customDio.dio.post(
        ApiRoutes.login,
        data: {
          'identity': id,
          'password': pw,
        },
      );
      if (res.statusCode == 200) {
        if (prefs != null) {
          prefs!.setString('token', res.data['token']);
        }
        var data = Map<String, dynamic>.from(res.data['record']);
        _profile(Profile.fromMap(data));
      }
    } on DioError catch (e) {
      print(e.message);
    }
  }

  logout() {
    var loginController = Get.find<LoginController>();
    if (prefs != null && loginController.prefs != null) {
      prefs!.clear();
      loginController.prefs!.clear();
    }
    loginController.formKey = GlobalKey<FormState>();
    Get.find<SignUpController>().formKey = GlobalKey<FormState>();
    _profile.value = null;
  }

  _handleAuthChanged(Profile? data) {
    if (data != null) {
      Get.toNamed(AppRoute.main);
      return;
    }
    Get.toNamed(AppRoute.login);
    return;
  }

  @override
  void onInit() {
    super.onInit();
    ever(_profile, _handleAuthChanged);
  }
}

login_controller.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/auth_controller.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LoginController extends GetxController {
  GlobalKey<FormState> formKey = GlobalKey<FormState>();
  TextEditingController idController = TextEditingController();
  TextEditingController pwController = TextEditingController();
  SharedPreferences? prefs;
  RxBool isIdPw = false.obs;
  var auth = Get.find<AuthController>();
  idCheck(String id) {
    if (id.isEmpty) {
      return 'id is required';
    }
    return null;
  }

  pwCheck(String pw) {
    if (pw.isEmpty) {
      return 'password is required';
    } else if (pw.length < 8) {
      return '9자 이상 입력하세요';
    } else {
      return null;
    }
  }

  login() {
    if (formKey.currentState!.validate()) {
      formKey.currentState!.save();
      auth.login(idController.text, pwController.text);
      if (prefs != null) {
        prefs!.setBool('isSave', isIdPw.value);
      }
    }
  }

  saveIdPw(bool? val) {
    if (val != null) {
      isIdPw(val);
    }
  }

  initPreference() async {
    prefs = await SharedPreferences.getInstance();
    if (prefs != null) {
      isIdPw(prefs!.getBool('isSave') ?? false);
      if (isIdPw.value) {
        auth.saveUser();
      }
    }
  }

  @override
  void onInit() {
    super.onInit();
    initPreference();
  }
}

secret_controller.dart

import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/model/secret.dart';
import 'package:secret_cat_app/util/api_routes.dart';
import 'package:secret_cat_app/util/custom_dio.dart';

class SecretController extends GetxController {
  final Rxn<List<Secret>> _secret = Rxn<List<Secret>>();
  final customDio = CustomDio();

  List<Secret>? get secret => _secret.value;
  readSecret() async {
    try {
      var res = await customDio.dio.get(
        ApiRoutes.secret,
      );
      if (res.statusCode == 200) {
        var data = List<Map<String, dynamic>>.from(res.data['items']);
        _secret(data.map((e) => Secret.fromMap(e)).toList());
      }
    } on DioError catch (e) {
      print(e.message);
    }
  }
  void onInit() {
    super.onInit();
    readSecret();
  }
}

sign_up_controller.dart

import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/auth_controller.dart';

class SignUpController extends GetxController {
  GlobalKey<FormState> formKey = GlobalKey<FormState>();
  var emailController = TextEditingController();
  var pwController = TextEditingController();
  var pwCheckController = TextEditingController();
  var nameController = TextEditingController();

  var auth = Get.find<AuthController>();
  start() {
    if (formKey.currentState!.validate()) {
      formKey.currentState!.save();
      auth.signUp(emailController.text, pwController.text,
          pwCheckController.text, nameController.text);
    }
  }

  emailCheck(String email) {
    if (email.isEmpty) {
      return 'Email is required';
    } else if (!RegExp(
            r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")
        .hasMatch(email)) {
      return 'Please enter a valid email address';
    }
    return null;
  }

  pwCheck(String pw) {
    if (pw.isEmpty) {
      return 'password is required';
    } else if (pw.length < 8) {
      return '9자 이상 입력하세요';
    } else {
      return null;
    }
  }

  pwDoubleCheck(String checkPw) {
    if (checkPw.isEmpty) {
      return 'password is required';
    } else if (checkPw.length < 8) {
      return '9자 이상 입력하세요';
    } else if (checkPw != pwController.text) {
      return '비밀번호가 다릅니다';
    } else {
      return null;
    }
  }
}

upload_controller.dart

import 'package:dio/dio.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/controller/auth_controller.dart';
import 'package:secret_cat_app/util/api_routes.dart';
import 'package:secret_cat_app/util/custom_dio.dart';
import 'package:secret_cat_app/util/routes.dart';

class UploadController extends GetxController {
  var inputController = TextEditingController();
  RxBool isName = false.obs;
  final customDio = CustomDio();

  startUpload() {
    if (inputController.text != '') {
      var auth = Get.find<AuthController>();
      isName.value
          ? secretUpload(
              inputController.text, auth.profile!.id, auth.profile!.username)
          : secretUpload(inputController.text);
    }
  }

  secretUpload(String secret,
      [String author = '', String authorName = '']) async {
    try {
      var res = await customDio.dio.post(
        ApiRoutes.upload,
        data: {'secret': secret, 'author ': author, 'authorName ': authorName},
      );
      if (res.statusCode == 200) {
        Get.snackbar('비밀공유 성공', '비밀이 업로드 되었습니다');
        Get.toNamed(AppRoute.main);
      }
    } on DioError catch (e) {
      print(e.message);
    }
  }

  checkName(bool? value) {
    if (value != null) {
      isName(value);
    }
  }
}

user_controller.dart

import 'package:dio/dio.dart';
import 'package:get/get.dart';
import 'package:secret_cat_app/model/user.dart';
import 'package:secret_cat_app/util/api_routes.dart';
import 'package:secret_cat_app/util/custom_dio.dart';

class UserController extends GetxController {
  final Rxn<List<User>> _users = Rxn<List<User>>();
  final customDio = CustomDio();

  List<User>? get users => _users.value;
  user() async {
    try {
      var res = await customDio.dio.get(
        ApiRoutes.user,
      );
      if (res.statusCode == 200) {
        var data = List<Map<String, dynamic>>.from(res.data['items']);
        _users(data.map((e) => User.fromMap(e)).toList());
      }
    } on DioError catch (e) {
      print(e.message);
    }
  }
    void onInit() {
    super.onInit();
    user();
  }
}

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  get: ^4.6.5
  dio: ^5.0.1
  font_awesome_flutter: ^10.4.0
  shared_preferences: ^2.0.18

  assets:
    - assets/images/

  fonts:
    - family: neo
      fonts:
        - asset: assets/fonts/neo.ttf