본문 바로가기

OpenWeather API를 이용한 플러터 앱 (2)

by 저긍 2024. 6. 12.
반응형

 

 
 
도시 추가, 수정, 삭제 기능을 구현 했다.

city.dart

class City {
  String name; // 도시 이름을 저장할 변수

  City(this.name); // 생성자: 도시 이름을 받아서 초기화
}

 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

add_city_screen.dart

import 'package:flutter/material.dart';

class AddCityScreen extends StatefulWidget {
  final Function(String) onAddCity; // 도시를 추가할 때 호출되는 콜백 함수

  AddCityScreen({required this.onAddCity}); // 생성자: 콜백 함수를 받아서 초기화

  @override
  _AddCityScreenState createState() => _AddCityScreenState(); // 상태를 생성
}

class _AddCityScreenState extends State<AddCityScreen> {
  final TextEditingController _controller = TextEditingController(); // 텍스트 필드 컨트롤러

  void _handleAddCity() {
    final cityName = _controller.text; // 텍스트 필드의 입력값을 가져옴
    if (cityName.isNotEmpty) {
      widget.onAddCity(cityName); // 콜백 함수 호출
      Navigator.of(context).pop(); // 화면 종료
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('도시 추가', style: TextStyle(color: Colors.white)), // 앱바 제목
        backgroundColor: Colors.lightBlue, // 앱바 배경색
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0), // 패딩 설정
        child: Column(
          children: [
            TextField(
              controller: _controller, // 텍스트 필드 컨트롤러 설정
              decoration: InputDecoration(labelText: '도시 이름 : 정확한 영어 이름으로 입력'), // 텍스트 필드 데코레이션
            ),
            SizedBox(height: 20), // 간격 추가
            ElevatedButton(
              onPressed: _handleAddCity, // 버튼 클릭 시 호출 함수
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all<Color>(Colors.lightBlue), // 버튼 배경색 설정
                foregroundColor: MaterialStateProperty.all<Color>(Colors.white), // 버튼 글자색 설정
              ),
              child: Text('여길 눌러 도시 추가'), // 버튼 텍스트
            ),
          ],
        ),
      ),
    );
  }
}

 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

city_detail_screen.dart

import 'package:flutter/material.dart';

class AddCityScreen extends StatefulWidget {
  final Function(String) onAddCity; // 도시를 추가할 때 호출되는 콜백 함수

  AddCityScreen({required this.onAddCity}); // 생성자: 콜백 함수를 받아서 초기화

  @override
  _AddCityScreenState createState() => _AddCityScreenState(); // 상태를 생성
}

class _AddCityScreenState extends State<AddCityScreen> {
  final TextEditingController _controller = TextEditingController(); // 텍스트 필드 컨트롤러

  void _handleAddCity() {
    final cityName = _controller.text; // 텍스트 필드의 입력값을 가져옴
    if (cityName.isNotEmpty) {
      widget.onAddCity(cityName); // 콜백 함수 호출
      Navigator.of(context).pop(); // 화면 종료
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('도시 추가', style: TextStyle(color: Colors.white)), // 앱바 제목
        backgroundColor: Colors.lightBlue, // 앱바 배경색
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0), // 패딩 설정
        child: Column(
          children: [
            TextField(
              controller: _controller, // 텍스트 필드 컨트롤러 설정
              decoration: InputDecoration(labelText: '도시 이름 : 정확한 영어 이름으로 입력'), // 텍스트 필드 데코레이션
            ),
            SizedBox(height: 20), // 간격 추가
            ElevatedButton(
              onPressed: _handleAddCity, // 버튼 클릭 시 호출 함수
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all<Color>(Colors.lightBlue), // 버튼 배경색 설정
                foregroundColor: MaterialStateProperty.all<Color>(Colors.white), // 버튼 글자색 설정
              ),
              child: Text('여길 눌러 도시 추가'), // 버튼 텍스트
            ),
          ],
        ),
      ),
    );
  }
}

 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

city_list_screen.dart

import 'package:flutter/material.dart';
import 'city_detail_screen.dart';
import '../models/city.dart';

class CityListScreen extends StatelessWidget {
  final List<City> cities; // 도시 목록
  final Function(City) removeCity; // 도시 제거 콜백 함수
  final Function(BuildContext, City) editCity; // 도시 수정 콜백 함수

  CityListScreen({
    required this.cities,
    required this.removeCity,
    required this.editCity,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('지금 날씨를 보자 !', style: TextStyle(color: Colors.white)), // 앱바 제목
        backgroundColor: Colors.lightBlue, // 앱바 배경색
      ),
      body: ListView.builder(
        itemCount: cities.length, // 도시 목록 길이
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(cities[index].name), // 도시 이름 표시
            trailing: Row(
              mainAxisSize: MainAxisSize.min, // 아이콘 버튼의 최소 크기 설정
              children: [
                IconButton(
                  icon: Icon(Icons.edit), // 수정 아이콘
                  onPressed: () {
                    editCity(context, cities[index]); // 수정 함수 호출
                  },
                ),
                IconButton(
                  icon: Icon(Icons.delete), // 삭제 아이콘
                  onPressed: () {
                    removeCity(cities[index]); // 삭제 함수 호출
                  },
                ),
              ],
            ),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => CityDetailScreen(city: cities[index]), // 상세 화면으로 이동
                ),
              );
            },
          );
        },
      ),
    );
  }
}

 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

edit_city_screen.dart

import 'package:flutter/material.dart';
import '../models/city.dart';

class EditCityScreen extends StatefulWidget {
  final City city; // 수정할 도시
  final Function(City, String) onEditCity; // 도시 수정 콜백 함수

  EditCityScreen({
    required this.city,
    required this.onEditCity,
  });

  @override
  _EditCityScreenState createState() => _EditCityScreenState(); // 상태를 생성
}

class _EditCityScreenState extends State<EditCityScreen> {
  late TextEditingController _controller; // 텍스트 필드 컨트롤러

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController(text: widget.city.name); // 초기 텍스트 설정
  }

  void _handleEditCity() {
    final newName = _controller.text; // 새 도시 이름을 가져옴
    if (newName.isNotEmpty) {
      widget.onEditCity(widget.city, newName); // 콜백 함수 호출
      Navigator.of(context).pop(); // 화면 종료
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('도시 수정', style: TextStyle(color: Colors.white)), // 앱바 제목
        backgroundColor: Colors.lightBlue, // 앱바 배경색
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0), // 패딩 설정
        child: Column(
          children: [
            TextField(
              controller: _controller, // 텍스트 필드 컨트롤러 설정
              decoration: InputDecoration(labelText: '도시 이름 : 정확한 영어 이름으로 입력'), // 텍스트 필드 데코레이션
            ),
            SizedBox(height: 20), // 간격 추가
            ElevatedButton(
              onPressed: _handleEditCity, // 버튼 클릭 시 호출 함수
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all<Color>(Colors.lightBlue), // 버튼 배경색 설정
                foregroundColor: MaterialStateProperty.all<Color>(Colors.white), // 버튼 글자색 설정
              ),
              child: Text('Save Changes'), // 버튼 텍스트
            ),
          ],
        ),
      ),
    );
  }
}

 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

home_screen.dart

import 'package:flutter/material.dart';
import 'city_list_screen.dart';
import 'add_city_screen.dart';
import 'edit_city_screen.dart'; // EditCityScreen 클래스 가져오기
import '../models/city.dart';

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState(); // 상태를 생성
}

class _HomeScreenState extends State<HomeScreen> {
  List<City> cities = [City('Seoul'), City('New York')]; // 초기 도시 목록

  void _addCity(String name) {
    setState(() {
      cities.add(City(name)); // 도시 추가
    });
  }

  void _removeCity(City city) {
    setState(() {
      cities.remove(city); // 도시 제거
    });
  }

  void _editCity(City city, String newName) {
    setState(() {
      city.name = newName; // 도시 이름 수정
    });
  }

  void _navigateToAddCityScreen(BuildContext context) {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => AddCityScreen(onAddCity: _addCity), // 도시 추가 화면으로 이동
      ),
    );
  }

  void _navigateToEditCityScreen(BuildContext context, City city) {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => EditCityScreen(city: city, onEditCity: _editCity), // 도시 수정 화면으로 이동
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          CityListScreen(
            cities: cities, // 도시 목록 전달
            removeCity: _removeCity, // 도시 제거 함수 전달
            editCity: _navigateToEditCityScreen, // 도시 수정 함수 전달
          ),
          Align(
            alignment: Alignment.bottomCenter, // 하단 가운데 정렬
            child: Padding(
              padding: const EdgeInsets.all(16.0), // 패딩 설정
              child: SizedBox(
                width: double.infinity,
                height: 80, // 버튼의 높이를 조정
                child: ElevatedButton(
                  onPressed: () => _navigateToAddCityScreen(context), // 버튼 클릭 시 호출 함수
                  style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all<Color>(Colors.lightBlue), // 버튼 배경색 설정
                    foregroundColor: MaterialStateProperty.all<Color>(Colors.white), // 버튼 글자색 설정
                  ),
                  child: Text(
                    '도시 추가',
                    style: TextStyle(fontSize: 24), // 버튼 텍스트 크기 조정
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

weather_service.dart

import 'package:http/http.dart' as http; // http 패키지를 가져와서 http로 명명
import 'dart:convert'; // JSON 인코딩 및 디코딩을 위한 패키지

class WeatherService {
  final String apiKey = '8f1aee2e4009fb6828780a625ee49123'; // OpenWeatherMap API 키

  // 도시 이름을 받아 날씨 데이터를 가져오는 비동기 함수
  Future<Map<String, dynamic>> fetchWeather(String city) async {
    // API 요청을 위한 URL 생성
    final response = await http.get(
      Uri.parse('https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$apiKey&units=metric'),
    );

    // HTTP 요청이 성공했는지 확인
    if (response.statusCode == 200) {
      return json.decode(response.body); // 성공 시, 응답 본문을 JSON 형식으로 디코딩하여 반환
    } else {
      throw Exception('Failed to load weather data'); // 실패 시, 예외 발생
    }
  }
}

 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

main.dart

import 'package:flutter/material.dart'; // Flutter의 Material Design 위젯 가져오기
import 'screens/home_screen.dart'; // 홈 화면 위젯 가져오기

void main() {
  runApp(MyApp()); // 앱 실행
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '지금 날씨를 보자!', // 앱 제목 설정
      theme: ThemeData(
        primarySwatch: Colors.blue, // 기본 테마 색상 설정
      ),
      home: HomeScreen(), // 홈 화면 위젯 설정
    );
  }
}
반응형

'' 카테고리의 다른 글

OpenWeather을 이용한 플러터 앱  (2) 2024.06.12