가끔 보자, 하늘.

Flutter 로 앱 개발 및 릴리즈 - 06. Settings 페이지 본문

개발 이야기/개발 및 서비스

Flutter 로 앱 개발 및 릴리즈 - 06. Settings 페이지

가온아 2025. 5. 14. 09:00

Settings 페이지에서는 Theme(System/Light/Dark), Language, Login/Logout, OpenSource list, 개발사 정보/website/SNS 정보를 추가해 보겠습니다. 

Gemin에게 요청:  setting_page.dart 페이지를 만들어줘. 다음과 같은 항목이 필요해. dark/light/system 선택, language 선택 로그인(구글, facebook, instagram, kakaotalk) / 로그인이 되어 있다면 로그인 된 sns 아이콘과 로그아웃 버튼, 오픈소스 리스트 보기 및 개발사 안내/홈페이지/sns 링크를 포함해줘.

setting_page.dart파일은 다음과 같습니다. 

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart'; // URL 링크 열기 위한 라이브러리

// URL 링크를 열기 위한 비동기 함수
Future<void> _launchUrl(String url) async {
  final Uri uri = Uri.parse(url);
  if (!await launchUrl(uri)) {
    throw Exception('Could not launch $uri');
  }
}

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

  @override
  State<SettingPage> createState() => _SettingPageState();
}

class _SettingPageState extends State<SettingPage> {
  // 상태 변수들
  String _selectedTheme = 'System'; // 현재 선택된 테마
  String _selectedLanguage = 'Korean'; // 현재 선택된 언어
  bool _isLoggedIn = false; // 로그인 상태 (예시)
  String _loggedInSns = ''; // 로그인된 SNS (예시: 'Google', 'Facebook' 등)

  // 테마 옵션
  final List<String> _themeOptions = ['System', 'Light', 'Dark'];
  // 언어 옵션 (실제 앱에서는 더 많은 언어를 지원할 수 있습니다)
  final List<String> _languageOptions = ['Korean', 'English'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Settings'),
      ),
      body: ListView( // 설정 항목들을 스크롤 가능하도록 ListView 사용
        children: [
          // 테마 선택
          ListTile(
            title: const Text('Theme'),
            trailing: DropdownButton<String>(
              value: _selectedTheme,
              onChanged: (String? newValue) {
                if (newValue != null) {
                  setState(() {
                    _selectedTheme = newValue;
                    // TODO: 실제로 앱의 테마를 변경하는 로직을 여기에 추가합니다.
                  });
                }
              },
              items: _themeOptions.map<DropdownMenuItem<String>>((String value) {
                return DropdownMenuItem<String>(
                  value: value,
                  child: Text(value),
                );
              }).toList(),
            ),
          ),
          const Divider(), // 구분선

          // 언어 선택
          ListTile(
            title: const Text('Language'),
            trailing: DropdownButton<String>(
              value: _selectedLanguage,
              onChanged: (String? newValue) {
                if (newValue != null) {
                  setState(() {
                    _selectedLanguage = newValue;
                    // TODO: 실제로 앱의 언어를 변경하는 로직을 여기에 추가합니다.
                  });
                }
              },
              items: _languageOptions.map<DropdownMenuItem<String>>((String value) {
                return DropdownMenuItem<String>(
                  value: value,
                  child: Text(value),
                );
              }).toList(),
            ),
          ),
          const Divider(), // 구분선

          // 로그인/로그아웃
          ListTile(
            title: Text(_isLoggedIn ? 'Logged in with $_loggedInSns' : 'Login'),
            trailing: _isLoggedIn
                ? IconButton(
              icon: const Icon(Icons.logout),
              onPressed: () {
                setState(() {
                  _isLoggedIn = false;
                  _loggedInSns = '';
                });
                // TODO: 로그아웃 처리 로직을 여기에 추가합니다.
                print('Logged out');
              },
            )
                : Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                // Google 로그인 버튼 (예시)
                IconButton(
                  icon: const Icon(Icons.account_circle, color: Colors.redAccent),
                  onPressed: () {
                    setState(() {
                      _isLoggedIn = true;
                      _loggedInSns = 'Google';
                    });
                    // TODO: Google 로그인 로직을 여기에 추가합니다.
                    print('Google Login');
                  },
                ),
                // Facebook 로그인 버튼 (예시)
                IconButton(
                  icon: const Icon(Icons.facebook, color: Colors.blueAccent),
                  onPressed: () {
                    setState(() {
                      _isLoggedIn = true;
                      _loggedInSns = 'Facebook';
                    });
                    // TODO: Facebook 로그인 로직을 여기에 추가합니다.
                    print('Facebook Login');
                  },
                ),
                // Instagram 로그인 버튼 (예시 - 적절한 아이콘을 사용해야 합니다)
                IconButton(
                  icon: const Icon(Icons.camera_alt, color: Colors.purpleAccent), // 예시 아이콘
                  onPressed: () {
                    setState(() {
                      _isLoggedIn = true;
                      _loggedInSns = 'Instagram';
                    });
                    // TODO: Instagram 로그인 로직을 여기에 추가합니다.
                    print('Instagram Login');
                  },
                ),
                // KakaoTalk 로그인 버튼 (예시 - 적절한 아이콘을 사용해야 합니다)
                IconButton(
                  icon: const Icon(Icons.chat, color: Colors.yellow), // 예시 아이콘
                  onPressed: () {
                    setState(() {
                      _isLoggedIn = true;
                      _loggedInSns = 'KakaoTalk';
                    });
                    // TODO: KakaoTalk 로그인 로직을 여기에 추가합니다.
                    print('KakaoTalk Login');
                  },
                ),
              ],
            ),
          ),
          const Divider(), // 구분선

          // 오픈소스 리스트 보기
          ListTile(
            title: const Text('View Open Source Licenses'),
            onTap: () {
              // TODO: 오픈소스 라이선스 목록 페이지로 이동하는 로직을 여기에 추가합니다.
              // Flutter는 기본적으로 오픈소스 라이선스 목록을 보여주는 페이지를 제공합니다.
              showLicensePage(context: context); // 기본 제공 페이지 사용 예시
              print('View Open Source Licenses');
            },
          ),
          const Divider(), // 구분선

          // 개발사 안내/홈페이지/SNS 링크
          const ListTile(
            title: Text('Developer Info'),
          ),
          ListTile(
            leading: const Icon(Icons.language),
            title: const Text('Website'),
            onTap: () {
              // TODO: 개발사 홈페이지 URL을 여기에 입력합니다.
              _launchUrl('https://developer.android.com/'); // 예시 URL
              print('Open Website');
            },
          ),
          ListTile(
            leading: const Icon(Icons.people), // 예시 아이콘
            title: const Text('SNS'),
            onTap: () {
              // TODO: 개발사 SNS URL을 여기에 입력합니다.
              _launchUrl('https://twitter.com/flutterdev'); // 예시 URL
              print('Open SNS');
            },
          ),
          const Divider(), // 구분선
        ],
      ),
    );
  }
}

이 코드에서 url_launcher를 위해 외부 컴포넌트를 사용합니다. 상세한 내용은 이 링크를 참고하세요. 

이제 navi_bar.dart를 다음과 같이 수정합니다.

import 'package:flutter/material.dart';
import 'calendar_page.dart';
import 'project_page.dart';
import 'setting_page.dart';
.
.
  final List<Widget> _pages = <Widget>[
    const CalendarPage(),
    const ProjectPage(),
    const SettingPage(),
  ];
  .
  .

그럼 다음과 같은 결과를 확인 하실 수 있습니다 .

이전까지 Claude 3.7 sonnet 만쓰다가 Gemini를 처음 사용해 봤는데 나쁘지 않은 듯 하네요. 앞으로 좀 더 써보면 뭐가 나올지 모르겠지만  지금까지는 만족스럽네요.

전체 프레임은 정리되었으니 이제 상세 기능을 하나씩 만들어가 보겠습니다. :)

반응형