GPT 개발/모바일 앱

ChatGPT로 모바일 앱 개발해보기(계산기 어플)

sdchjjj 2024. 11. 29. 19:08
반응형

안녕하세요. 

 

요즘 GPT를 활용하는 개발자의 빈도가 아주 많이 늘어나고 있다고 합니다. 이 트렌드에 합류하여 저 또한 GPT에게 받은 답을 토대로 앱을 개발해 보겠습니다.

 

그 어떤 개입도 하지 않은 순수 GPT 답변으로만 작성된 코드를 사용하겠습니다. 물론 GPT에게 설계에 관한 언급도 하지 않을 예정입니다.

 

이번 포스팅에서 GPT를 통해 만들어볼 앱은 계산기 앱입니다. 최종 결과물은 가장 하단의 소스를 확인하시면 됩니다.

 

언어: dart

IDE: Android Studio

Framework: Flutter

Test device: Android

GPT model: GPT-4o

 

질문을 합니다.

figure 1

답변은 물론 가능하다고 합니다.

 

아래는 GPT에게 받은 코드입니다.

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(CalculatorApp());
}

class CalculatorApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Calculator',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CalculatorHome(),
    );
  }
}

class CalculatorHome extends StatefulWidget {
  @override
  _CalculatorHomeState createState() => _CalculatorHomeState();
}

class _CalculatorHomeState extends State<CalculatorHome> {
  String _output = "0";
  String _currentValue = "";
  String _operation = "";
  double? _firstNumber;
  double? _secondNumber;

  void _buttonPressed(String value) {
    setState(() {
      if (value == "C") {
        _output = "0";
        _currentValue = "";
        _operation = "";
        _firstNumber = null;
        _secondNumber = null;
      } else if (value == "+" || value == "-" || value == "*" || value == "/") {
        if (_firstNumber == null) {
          _firstNumber = double.tryParse(_currentValue) ?? 0;
          _operation = value;
          _currentValue = "";
        }
      } else if (value == "=") {
        if (_operation.isNotEmpty && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          if (_secondNumber != null) {
            switch (_operation) {
              case "+":
                _output = (_firstNumber! + _secondNumber!).toString();
                break;
              case "-":
                _output = (_firstNumber! - _secondNumber!).toString();
                break;
              case "*":
                _output = (_firstNumber! * _secondNumber!).toString();
                break;
              case "/":
                _output = (_secondNumber != 0)
                    ? (_firstNumber! / _secondNumber!).toString()
                    : "Error";
                break;
            }
          }
          _currentValue = _output;
          _firstNumber = null;
          _secondNumber = null;
          _operation = "";
        }
      } else {
        _currentValue += value;
        _output = _currentValue;
      }
    });
  }

  Widget _buildButton(String label) {
    return Expanded(
      child: ElevatedButton(
        onPressed: () => _buttonPressed(label),
        child: Text(
          label,
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Calculator'),
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              alignment: Alignment.centerRight,
              padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
              color: Colors.black12,
              child: Text(
                _output,
                style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
              ),
            ),
          ),
          Expanded(
            flex: 2,
            child: Column(
              children: [
                Row(
                  children: [
                    _buildButton("7"),
                    _buildButton("8"),
                    _buildButton("9"),
                    _buildButton("/")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("4"),
                    _buildButton("5"),
                    _buildButton("6"),
                    _buildButton("*")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("1"),
                    _buildButton("2"),
                    _buildButton("3"),
                    _buildButton("-")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("C"),
                    _buildButton("0"),
                    _buildButton("="),
                    _buildButton("+")
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

 

계산기처럼 동작은 하지만 어딘가 허술합니다. 일단 발견한 문제점을 나열해 보겠습니다.

 1. 계산 기호를 클릭 후 새로운 숫자를 입력하면 기존에 입력했던 숫자가 사라진다(figure2 참조. 물론 이런 방식의 계산기가 있기는 하지만 이 부분도 수정해 보겠음).

 2. 정수만 사용했는데 계속 결과 뒤에 소수점이 붙는다(figure2 참조. 결과가 정수임에도 불구하고 뒤에 '.0'이 붙음).

figure 2

 3. 결과가 나온 상태에서 숫자를 입력하면 소수점 뒤로 그 숫자가 붙는다(figure3 참조. 결과가 10.0인 상태라면 여기에 2, 3 등을 입력하면 10.023 이렇게 값이 바뀐다).

figure 3

하나씩 수정을 요청해 보겠습니다.

먼저 1번에 대한 요청입니다.

figure 4

모든 과정을 보여달라고 요청했습니다.

아래는 수정된 코드입니다.

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(CalculatorApp());
}

class CalculatorApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Calculator',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CalculatorHome(),
    );
  }
}

class CalculatorHome extends StatefulWidget {
  @override
  _CalculatorHomeState createState() => _CalculatorHomeState();
}

class _CalculatorHomeState extends State<CalculatorHome> {
  String _display = "0"; // Full display for the user
  String _currentValue = ""; // Current input value
  String _operation = ""; // Current arithmetic operation
  double? _firstNumber; // First operand
  double? _secondNumber; // Second operand

  void _buttonPressed(String value) {
    setState(() {
      if (value == "C") {
        _display = "0";
        _currentValue = "";
        _operation = "";
        _firstNumber = null;
        _secondNumber = null;
      } else if (value == "+" || value == "-" || value == "*" || value == "/") {
        if (_currentValue.isNotEmpty) {
          if (_firstNumber == null) {
            _firstNumber = double.tryParse(_currentValue) ?? 0;
            _operation = value;
            _display = "$_firstNumber $_operation";
            _currentValue = "";
          } else if (_secondNumber == null && _currentValue.isNotEmpty) {
            _secondNumber = double.tryParse(_currentValue);
            if (_secondNumber != null) {
              _calculateResult();
              _operation = value;
              _display = "$_display $_operation";
            }
          }
        }
      } else if (value == "=") {
        if (_firstNumber != null && _operation.isNotEmpty && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          if (_secondNumber != null) {
            _calculateResult();
            _operation = "";
          }
        }
      } else {
        // Handle number input
        _currentValue += value;
        if (_operation.isEmpty) {
          _display = _currentValue; // Display number if no operation yet
        } else {
          _display = "$_firstNumber $_operation $_currentValue";
        }
      }
    });
  }

  void _calculateResult() {
    double? result;
    switch (_operation) {
      case "+":
        result = _firstNumber! + _secondNumber!;
        break;
      case "-":
        result = _firstNumber! - _secondNumber!;
        break;
      case "*":
        result = _firstNumber! * _secondNumber!;
        break;
      case "/":
        result = (_secondNumber != 0) ? _firstNumber! / _secondNumber! : double.nan;
        break;
    }

    if (result != null) {
      _display = "$_firstNumber $_operation $_secondNumber = $result";
      _firstNumber = result;
      _secondNumber = null;
      _currentValue = "";
    }
  }

  Widget _buildButton(String label) {
    return Expanded(
      child: ElevatedButton(
        onPressed: () => _buttonPressed(label),
        child: Text(
          label,
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Calculator'),
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              alignment: Alignment.centerRight,
              padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
              color: Colors.black12,
              child: Text(
                _display,
                style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
                textAlign: TextAlign.right,
              ),
            ),
          ),
          Expanded(
            flex: 2,
            child: Column(
              children: [
                Row(
                  children: [
                    _buildButton("7"),
                    _buildButton("8"),
                    _buildButton("9"),
                    _buildButton("/")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("4"),
                    _buildButton("5"),
                    _buildButton("6"),
                    _buildButton("*")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("1"),
                    _buildButton("2"),
                    _buildButton("3"),
                    _buildButton("-")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("C"),
                    _buildButton("0"),
                    _buildButton("="),
                    _buildButton("+")
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

 

어디가 어떻게 수정되었는지 확인은 미뤄두고 결과 먼저 보겠습니다.

figure 5

잘 수정이 되었습니다.

이제 소수점 부분을 고쳐보겠습니다.

figure 6

수정해 준 코드입니다.

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(CalculatorApp());
}

class CalculatorApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Calculator',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CalculatorHome(),
    );
  }
}

class CalculatorHome extends StatefulWidget {
  @override
  _CalculatorHomeState createState() => _CalculatorHomeState();
}

class _CalculatorHomeState extends State<CalculatorHome> {
  String _display = "0"; // Full display for the user
  String _currentValue = ""; // Current input value
  String _operation = ""; // Current arithmetic operation
  double? _firstNumber; // First operand
  double? _secondNumber; // Second operand

  void _buttonPressed(String value) {
    setState(() {
      if (value == "C") {
        _display = "0";
        _currentValue = "";
        _operation = "";
        _firstNumber = null;
        _secondNumber = null;
      } else if (value == "+" || value == "-" || value == "*" || value == "/") {
        if (_currentValue.isNotEmpty) {
          if (_firstNumber == null) {
            _firstNumber = double.tryParse(_currentValue) ?? 0;
            _operation = value;
            _display = "${_formatNumber(_firstNumber!)} $_operation";
            _currentValue = "";
          } else if (_secondNumber == null && _currentValue.isNotEmpty) {
            _secondNumber = double.tryParse(_currentValue);
            if (_secondNumber != null) {
              _calculateResult();
              _operation = value;
              _display = "$_display $_operation";
            }
          }
        }
      } else if (value == "=") {
        if (_firstNumber != null && _operation.isNotEmpty && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          if (_secondNumber != null) {
            _calculateResult();
            _operation = "";
          }
        }
      } else {
        // Handle number input
        _currentValue += value;
        if (_operation.isEmpty) {
          _display = _currentValue; // Display number if no operation yet
        } else {
          _display = "${_formatNumber(_firstNumber!)} $_operation $_currentValue";
        }
      }
    });
  }

  void _calculateResult() {
    double? result;
    switch (_operation) {
      case "+":
        result = _firstNumber! + _secondNumber!;
        break;
      case "-":
        result = _firstNumber! - _secondNumber!;
        break;
      case "*":
        result = _firstNumber! * _secondNumber!;
        break;
      case "/":
        result = (_secondNumber != 0) ? _firstNumber! / _secondNumber! : double.nan;
        break;
    }

    if (result != null) {
      _display = "${_formatNumber(_firstNumber!)} $_operation ${_formatNumber(_secondNumber!)} = ${_formatNumber(result)}";
      _firstNumber = result;
      _secondNumber = null;
      _currentValue = "";
    }
  }

  String _formatNumber(double value) {
    if (value == value.toInt()) {
      // Check if the value is an integer
      return value.toInt().toString();
    } else {
      return value.toString();
    }
  }

  Widget _buildButton(String label) {
    return Expanded(
      child: ElevatedButton(
        onPressed: () => _buttonPressed(label),
        child: Text(
          label,
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Calculator'),
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              alignment: Alignment.centerRight,
              padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
              color: Colors.black12,
              child: Text(
                _display,
                style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
                textAlign: TextAlign.right,
              ),
            ),
          ),
          Expanded(
            flex: 2,
            child: Column(
              children: [
                Row(
                  children: [
                    _buildButton("7"),
                    _buildButton("8"),
                    _buildButton("9"),
                    _buildButton("/")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("4"),
                    _buildButton("5"),
                    _buildButton("6"),
                    _buildButton("*")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("1"),
                    _buildButton("2"),
                    _buildButton("3"),
                    _buildButton("-")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("C"),
                    _buildButton("0"),
                    _buildButton("="),
                    _buildButton("+")
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

 

확인해 보겠습니다.

figure 7

결과는 성공적입니다.

 

마지막 요청입니다. 결과가 나온 뒤 새로운 숫자가 입력되면 기존의 결과가 초기화되도록 요청하겠습니다.

figure 8

빠르게 수정되어 반영을 해보겠습니다.

 

아래는 수정본입니다.

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(CalculatorApp());
}

class CalculatorApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Calculator',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CalculatorHome(),
    );
  }
}

class CalculatorHome extends StatefulWidget {
  @override
  _CalculatorHomeState createState() => _CalculatorHomeState();
}

class _CalculatorHomeState extends State<CalculatorHome> {
  String _display = "0"; // Full display for the user
  String _currentValue = ""; // Current input value
  String _operation = ""; // Current arithmetic operation
  double? _firstNumber; // First operand
  double? _secondNumber; // Second operand
  bool _resetOnNextInput = false; // Flag to reset state on new input

  void _buttonPressed(String value) {
    setState(() {
      if (_resetOnNextInput && _isDigit(value)) {
        // Reset everything if a new number is pressed after a result
        _clearAll();
      }

      if (value == "C") {
        _clearAll();
      } else if (value == "+" || value == "-" || value == "*" || value == "/") {
        if (_currentValue.isNotEmpty) {
          if (_firstNumber == null) {
            _firstNumber = double.tryParse(_currentValue) ?? 0;
            _operation = value;
            _display = "${_formatNumber(_firstNumber!)} $_operation";
            _currentValue = "";
            _resetOnNextInput = false;
          } else if (_secondNumber == null && _currentValue.isNotEmpty) {
            _secondNumber = double.tryParse(_currentValue);
            if (_secondNumber != null) {
              _calculateResult();
              _operation = value;
              _display = "$_display $_operation";
              _resetOnNextInput = false;
            }
          }
        }
      } else if (value == "=") {
        if (_firstNumber != null && _operation.isNotEmpty && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          if (_secondNumber != null) {
            _calculateResult();
            _operation = "";
            _resetOnNextInput = true;
          }
        }
      } else {
        // Handle number input
        if (_resetOnNextInput) {
          _clearAll(); // Reset the state if needed
        }
        _currentValue += value;
        if (_operation.isEmpty) {
          _display = _currentValue; // Display number if no operation yet
        } else {
          _display = "${_formatNumber(_firstNumber!)} $_operation $_currentValue";
        }
      }
    });
  }

  bool _isDigit(String value) {
    // Check if the button pressed is a digit
    return RegExp(r'^[0-9]$').hasMatch(value);
  }

  void _clearAll() {
    _display = "0";
    _currentValue = "";
    _operation = "";
    _firstNumber = null;
    _secondNumber = null;
    _resetOnNextInput = false;
  }

  void _calculateResult() {
    double? result;
    switch (_operation) {
      case "+":
        result = _firstNumber! + _secondNumber!;
        break;
      case "-":
        result = _firstNumber! - _secondNumber!;
        break;
      case "*":
        result = _firstNumber! * _secondNumber!;
        break;
      case "/":
        result = (_secondNumber != 0) ? _firstNumber! / _secondNumber! : double.nan;
        break;
    }

    if (result != null) {
      _display = "${_formatNumber(_firstNumber!)} $_operation ${_formatNumber(_secondNumber!)} = ${_formatNumber(result)}";
      _firstNumber = result;
      _secondNumber = null;
      _currentValue = "";
      _resetOnNextInput = true;
    }
  }

  String _formatNumber(double value) {
    if (value == value.toInt()) {
      // Check if the value is an integer
      return value.toInt().toString();
    } else {
      return value.toString();
    }
  }

  Widget _buildButton(String label) {
    return Expanded(
      child: ElevatedButton(
        onPressed: () => _buttonPressed(label),
        child: Text(
          label,
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Calculator'),
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              alignment: Alignment.centerRight,
              padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
              color: Colors.black12,
              child: Text(
                _display,
                style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
                textAlign: TextAlign.right,
              ),
            ),
          ),
          Expanded(
            flex: 2,
            child: Column(
              children: [
                Row(
                  children: [
                    _buildButton("7"),
                    _buildButton("8"),
                    _buildButton("9"),
                    _buildButton("/")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("4"),
                    _buildButton("5"),
                    _buildButton("6"),
                    _buildButton("*")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("1"),
                    _buildButton("2"),
                    _buildButton("3"),
                    _buildButton("-")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("C"),
                    _buildButton("0"),
                    _buildButton("="),
                    _buildButton("+")
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

 

바로 결과를 확인해 봅니다.

figure 9

원했던 대로 수정이 되었습니다.

그런데 여기서 또 다른 문제가 발견되었습니다. 기존의 결과에 추가로 수식이 이어지지 않는다는 것입니다. 결과가 나왔어도 그 값에 추가로 더하기 빼기 등을 진행할 수 있어야 합니다.

 

이 부분, 추가로 요청해 보겠습니다.

figure 10

답변으로 받은 코드입니다.

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(CalculatorApp());
}

class CalculatorApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Calculator',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CalculatorHome(),
    );
  }
}

class CalculatorHome extends StatefulWidget {
  @override
  _CalculatorHomeState createState() => _CalculatorHomeState();
}

class _CalculatorHomeState extends State<CalculatorHome> {
  String _display = "0"; // Full display for the user
  String _currentValue = ""; // Current input value
  String _operation = ""; // Current arithmetic operation
  double? _firstNumber; // First operand
  double? _secondNumber; // Second operand
  bool _readyForNextInput = false; // Flag to indicate readiness for next input

  void _buttonPressed(String value) {
    setState(() {
      if (value == "C") {
        _clearAll();
      } else if (value == "+" || value == "-" || value == "*" || value == "/") {
        // If an operator is clicked
        if (_firstNumber == null && _currentValue.isNotEmpty) {
          _firstNumber = double.tryParse(_currentValue);
          _operation = value;
          _display = _formatNumber(_firstNumber!);
          _currentValue = "";
          _readyForNextInput = true;
        } else if (_firstNumber != null && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          _calculateResult();
          _operation = value;
          _readyForNextInput = true;
        } else if (_firstNumber != null) {
          _operation = value;
        }
      } else if (value == "=") {
        // If '=' is clicked
        if (_firstNumber != null && _operation.isNotEmpty && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          _calculateResult();
          _operation = "";
          _readyForNextInput = true;
        }
      } else {
        // Handle number input
        if (_readyForNextInput) {
          _currentValue = ""; // Reset the input if ready for new input
          _readyForNextInput = false;
        }
        _currentValue += value;
        _display = _currentValue;
      }
    });
  }

  void _clearAll() {
    _display = "0";
    _currentValue = "";
    _operation = "";
    _firstNumber = null;
    _secondNumber = null;
    _readyForNextInput = false;
  }

  void _calculateResult() {
    if (_operation.isEmpty || _secondNumber == null) return;

    double? result;
    switch (_operation) {
      case "+":
        result = _firstNumber! + _secondNumber!;
        break;
      case "-":
        result = _firstNumber! - _secondNumber!;
        break;
      case "*":
        result = _firstNumber! * _secondNumber!;
        break;
      case "/":
        result = (_secondNumber != 0) ? _firstNumber! / _secondNumber! : double.nan;
        break;
    }

    if (result != null) {
      _firstNumber = result;
      _currentValue = "";
      _display = _formatNumber(result);
      _secondNumber = null;
    }
  }

  String _formatNumber(double value) {
    if (value == value.toInt()) {
      // Check if the value is an integer
      return value.toInt().toString();
    } else {
      return value.toString();
    }
  }

  Widget _buildButton(String label) {
    return Expanded(
      child: ElevatedButton(
        onPressed: () => _buttonPressed(label),
        child: Text(
          label,
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Calculator'),
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              alignment: Alignment.centerRight,
              padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
              color: Colors.black12,
              child: Text(
                _display,
                style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
                textAlign: TextAlign.right,
              ),
            ),
          ),
          Expanded(
            flex: 2,
            child: Column(
              children: [
                Row(
                  children: [
                    _buildButton("7"),
                    _buildButton("8"),
                    _buildButton("9"),
                    _buildButton("/")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("4"),
                    _buildButton("5"),
                    _buildButton("6"),
                    _buildButton("*")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("1"),
                    _buildButton("2"),
                    _buildButton("3"),
                    _buildButton("-")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("C"),
                    _buildButton("0"),
                    _buildButton("="),
                    _buildButton("+")
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

 

figure 11

원했던 대로 수정이 되었지만 다시 과정이 보이지 않게 되었습니다.

아무래도 제 질문에 문제가 있었던 것 같습니다.

정상화해 보겠습니다.

figure 12

 

친절하게 아래와 같이 다시 수정해 주었습니다.

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(CalculatorApp());
}

class CalculatorApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Calculator',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CalculatorHome(),
    );
  }
}

class CalculatorHome extends StatefulWidget {
  @override
  _CalculatorHomeState createState() => _CalculatorHomeState();
}

class _CalculatorHomeState extends State<CalculatorHome> {
  String _display = "0"; // Full display for the user
  String _currentValue = ""; // Current input value
  String _operation = ""; // Current arithmetic operation
  double? _firstNumber; // First operand
  double? _secondNumber; // Second operand
  bool _readyForNextInput = false; // Flag to indicate readiness for next input

  void _buttonPressed(String value) {
    setState(() {
      if (value == "C") {
        _clearAll();
      } else if (value == "+" || value == "-" || value == "*" || value == "/") {
        if (_firstNumber == null && _currentValue.isNotEmpty) {
          // Set the first number and the operation
          _firstNumber = double.tryParse(_currentValue);
          _operation = value;
          _display = "${_formatNumber(_firstNumber!)} $_operation";
          _currentValue = "";
          _readyForNextInput = false;
        } else if (_firstNumber != null && _currentValue.isNotEmpty) {
          // Calculate the result with the second number
          _secondNumber = double.tryParse(_currentValue);
          _calculateResult();
          _operation = value;
          _display = "${_formatNumber(_firstNumber!)} $_operation";
          _readyForNextInput = false;
        } else if (_firstNumber != null) {
          // Allow chaining operators
          _operation = value;
          _display = "${_formatNumber(_firstNumber!)} $_operation";
        }
      } else if (value == "=") {
        if (_firstNumber != null && _operation.isNotEmpty && _currentValue.isNotEmpty) {
          // Calculate the result and display the full process
          _secondNumber = double.tryParse(_currentValue);
          _calculateResult();
          _operation = "";
          _readyForNextInput = true;
        }
      } else {
        // Handle number input
        if (_readyForNextInput) {
          _clearForNextCalculation();
        }
        _currentValue += value;
        if (_operation.isEmpty) {
          _display = _currentValue; // Show the current value if no operation yet
        } else {
          _display = "${_formatNumber(_firstNumber!)} $_operation $_currentValue";
        }
      }
    });
  }

  void _clearAll() {
    _display = "0";
    _currentValue = "";
    _operation = "";
    _firstNumber = null;
    _secondNumber = null;
    _readyForNextInput = false;
  }

  void _clearForNextCalculation() {
    // Clear only input-related fields while retaining the first number
    _currentValue = "";
    _readyForNextInput = false;
  }

  void _calculateResult() {
    if (_operation.isEmpty || _secondNumber == null) return;

    double? result;
    switch (_operation) {
      case "+":
        result = _firstNumber! + _secondNumber!;
        break;
      case "-":
        result = _firstNumber! - _secondNumber!;
        break;
      case "*":
        result = _firstNumber! * _secondNumber!;
        break;
      case "/":
        result = (_secondNumber != 0) ? _firstNumber! / _secondNumber! : double.nan;
        break;
    }

    if (result != null) {
      _display =
      "${_formatNumber(_firstNumber!)} $_operation ${_formatNumber(_secondNumber!)} = ${_formatNumber(result)}";
      _firstNumber = result;
      _secondNumber = null;
      _currentValue = "";
    }
  }

  String _formatNumber(double value) {
    if (value == value.toInt()) {
      // Check if the value is an integer
      return value.toInt().toString();
    } else {
      return value.toString();
    }
  }

  Widget _buildButton(String label) {
    return Expanded(
      child: ElevatedButton(
        onPressed: () => _buttonPressed(label),
        child: Text(
          label,
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Calculator'),
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              alignment: Alignment.centerRight,
              padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
              color: Colors.black12,
              child: Text(
                _display,
                style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
                textAlign: TextAlign.right,
              ),
            ),
          ),
          Expanded(
            flex: 2,
            child: Column(
              children: [
                Row(
                  children: [
                    _buildButton("7"),
                    _buildButton("8"),
                    _buildButton("9"),
                    _buildButton("/")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("4"),
                    _buildButton("5"),
                    _buildButton("6"),
                    _buildButton("*")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("1"),
                    _buildButton("2"),
                    _buildButton("3"),
                    _buildButton("-")
                  ],
                ),
                Row(
                  children: [
                    _buildButton("C"),
                    _buildButton("0"),
                    _buildButton("="),
                    _buildButton("+")
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

 

결과를 보겠습니다.

figuer 13

이제야 그럴듯한 계산기처럼 보입니다.

 

여기서 그치지 않고 한 단계 더 나아가, GPT의 미적 감각까지 확인해 보겠습니다.

아래와 같은 질문을 합니다.

figure 14

 

내놓은 답변은 아래와 같습니다.

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(CalculatorApp());
}

class CalculatorApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Beautiful Calculator',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CalculatorHome(),
    );
  }
}

class CalculatorHome extends StatefulWidget {
  @override
  _CalculatorHomeState createState() => _CalculatorHomeState();
}

class _CalculatorHomeState extends State<CalculatorHome> {
  String _display = "0";
  String _currentValue = "";
  String _operation = "";
  double? _firstNumber;
  double? _secondNumber;
  bool _readyForNextInput = false;

  void _buttonPressed(String value) {
    setState(() {
      if (value == "C") {
        _clearAll();
      } else if (value == "+" || value == "-" || value == "*" || value == "/") {
        if (_firstNumber == null && _currentValue.isNotEmpty) {
          _firstNumber = double.tryParse(_currentValue);
          _operation = value;
          _display = "${_formatNumber(_firstNumber!)} $_operation";
          _currentValue = "";
          _readyForNextInput = false;
        } else if (_firstNumber != null && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          _calculateResult();
          _operation = value;
          _display = "${_formatNumber(_firstNumber!)} $_operation";
          _readyForNextInput = false;
        } else if (_firstNumber != null) {
          _operation = value;
          _display = "${_formatNumber(_firstNumber!)} $_operation";
        }
      } else if (value == "=") {
        if (_firstNumber != null && _operation.isNotEmpty && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          _calculateResult();
          _operation = "";
          _readyForNextInput = true;
        }
      } else {
        if (_readyForNextInput) {
          _clearForNextCalculation();
        }
        _currentValue += value;
        if (_operation.isEmpty) {
          _display = _currentValue;
        } else {
          _display = "${_formatNumber(_firstNumber!)} $_operation $_currentValue";
        }
      }
    });
  }

  void _clearAll() {
    _display = "0";
    _currentValue = "";
    _operation = "";
    _firstNumber = null;
    _secondNumber = null;
    _readyForNextInput = false;
  }

  void _clearForNextCalculation() {
    _currentValue = "";
    _readyForNextInput = false;
  }

  void _calculateResult() {
    if (_operation.isEmpty || _secondNumber == null) return;

    double? result;
    switch (_operation) {
      case "+":
        result = _firstNumber! + _secondNumber!;
        break;
      case "-":
        result = _firstNumber! - _secondNumber!;
        break;
      case "*":
        result = _firstNumber! * _secondNumber!;
        break;
      case "/":
        result = (_secondNumber != 0) ? _firstNumber! / _secondNumber! : double.nan;
        break;
    }

    if (result != null) {
      _display =
      "${_formatNumber(_firstNumber!)} $_operation ${_formatNumber(_secondNumber!)} = ${_formatNumber(result)}";
      _firstNumber = result;
      _secondNumber = null;
      _currentValue = "";
    }
  }

  String _formatNumber(double value) {
    if (value == value.toInt()) {
      return value.toInt().toString();
    } else {
      return value.toString();
    }
  }

  Widget _buildButton(String label, Color color) {
    return Expanded(
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: ElevatedButton(
          style: ElevatedButton.styleFrom(
            primary: color,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(16),
            ),
            padding: EdgeInsets.all(24),
          ),
          onPressed: () => _buttonPressed(label),
          child: Text(
            label,
            style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[900],
      appBar: AppBar(
        title: Text('Beautiful Calculator'),
        backgroundColor: Colors.grey[850],
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              alignment: Alignment.centerRight,
              padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
              color: Colors.black12,
              child: Text(
                _display,
                style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold, color: Colors.white),
                textAlign: TextAlign.right,
              ),
            ),
          ),
          Expanded(
            flex: 3,
            child: Column(
              children: [
                Row(
                  children: [
                    _buildButton("7", Colors.blueGrey),
                    _buildButton("8", Colors.blueGrey),
                    _buildButton("9", Colors.blueGrey),
                    _buildButton("/", Colors.orange),
                  ],
                ),
                Row(
                  children: [
                    _buildButton("4", Colors.blueGrey),
                    _buildButton("5", Colors.blueGrey),
                    _buildButton("6", Colors.blueGrey),
                    _buildButton("*", Colors.orange),
                  ],
                ),
                Row(
                  children: [
                    _buildButton("1", Colors.blueGrey),
                    _buildButton("2", Colors.blueGrey),
                    _buildButton("3", Colors.blueGrey),
                    _buildButton("-", Colors.orange),
                  ],
                ),
                Row(
                  children: [
                    _buildButton("C", Colors.red),
                    _buildButton("0", Colors.blueGrey),
                    _buildButton("=", Colors.green),
                    _buildButton("+", Colors.orange),
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

 

하지만 에러가 발생합니다.

 

131번 라인 primary 부분에서 문제가 나왔습니다.

primary: color,

 

이것 역시 GPT에게 맡깁니다.

figure 15

빠르게 해결책을 주었습니다.

 

문제가 발생했던 _buildButton Widget을 아래와 같이 수정해 줍니다.

main.dart/_buildButton

Widget _buildButton(String label, Color color) {
  return Expanded(
    child: Padding(
      padding: const EdgeInsets.all(8.0),
      child: ElevatedButton(
        style: ElevatedButton.styleFrom(
          backgroundColor: color, // Replaces `primary` with `backgroundColor`
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16),
          ),
          padding: EdgeInsets.all(24),
        ),
        onPressed: () => _buttonPressed(label),
        child: Text(
          label,
          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
        ),
      ),
    ),
  );
}

이제 에러가 사라졌습니다.

 

아래는 전체 코드입니다.

main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(CalculatorApp());
}

class CalculatorApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Beautiful Calculator',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CalculatorHome(),
    );
  }
}

class CalculatorHome extends StatefulWidget {
  @override
  _CalculatorHomeState createState() => _CalculatorHomeState();
}

class _CalculatorHomeState extends State<CalculatorHome> {
  String _display = "0";
  String _currentValue = "";
  String _operation = "";
  double? _firstNumber;
  double? _secondNumber;
  bool _readyForNextInput = false;

  void _buttonPressed(String value) {
    setState(() {
      if (value == "C") {
        _clearAll();
      } else if (value == "+" || value == "-" || value == "*" || value == "/") {
        if (_firstNumber == null && _currentValue.isNotEmpty) {
          _firstNumber = double.tryParse(_currentValue);
          _operation = value;
          _display = "${_formatNumber(_firstNumber!)} $_operation";
          _currentValue = "";
          _readyForNextInput = false;
        } else if (_firstNumber != null && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          _calculateResult();
          _operation = value;
          _display = "${_formatNumber(_firstNumber!)} $_operation";
          _readyForNextInput = false;
        } else if (_firstNumber != null) {
          _operation = value;
          _display = "${_formatNumber(_firstNumber!)} $_operation";
        }
      } else if (value == "=") {
        if (_firstNumber != null && _operation.isNotEmpty && _currentValue.isNotEmpty) {
          _secondNumber = double.tryParse(_currentValue);
          _calculateResult();
          _operation = "";
          _readyForNextInput = true;
        }
      } else {
        if (_readyForNextInput) {
          _clearForNextCalculation();
        }
        _currentValue += value;
        if (_operation.isEmpty) {
          _display = _currentValue;
        } else {
          _display = "${_formatNumber(_firstNumber!)} $_operation $_currentValue";
        }
      }
    });
  }

  void _clearAll() {
    _display = "0";
    _currentValue = "";
    _operation = "";
    _firstNumber = null;
    _secondNumber = null;
    _readyForNextInput = false;
  }

  void _clearForNextCalculation() {
    _currentValue = "";
    _readyForNextInput = false;
  }

  void _calculateResult() {
    if (_operation.isEmpty || _secondNumber == null) return;

    double? result;
    switch (_operation) {
      case "+":
        result = _firstNumber! + _secondNumber!;
        break;
      case "-":
        result = _firstNumber! - _secondNumber!;
        break;
      case "*":
        result = _firstNumber! * _secondNumber!;
        break;
      case "/":
        result = (_secondNumber != 0) ? _firstNumber! / _secondNumber! : double.nan;
        break;
    }

    if (result != null) {
      _display =
      "${_formatNumber(_firstNumber!)} $_operation ${_formatNumber(_secondNumber!)} = ${_formatNumber(result)}";
      _firstNumber = result;
      _secondNumber = null;
      _currentValue = "";
    }
  }

  String _formatNumber(double value) {
    if (value == value.toInt()) {
      return value.toInt().toString();
    } else {
      return value.toString();
    }
  }

  Widget _buildButton(String label, Color color) {
    return Expanded(
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: ElevatedButton(
          style: ElevatedButton.styleFrom(
            backgroundColor: color, // Replaces `primary` with `backgroundColor`
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(16),
            ),
            padding: EdgeInsets.all(24),
          ),
          onPressed: () => _buttonPressed(label),
          child: Text(
            label,
            style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
          ),
        ),
      ),
    );
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[900],
      appBar: AppBar(
        title: Text('Beautiful Calculator'),
        backgroundColor: Colors.grey[850],
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              alignment: Alignment.centerRight,
              padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
              color: Colors.black12,
              child: Text(
                _display,
                style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold, color: Colors.white),
                textAlign: TextAlign.right,
              ),
            ),
          ),
          Expanded(
            flex: 3,
            child: Column(
              children: [
                Row(
                  children: [
                    _buildButton("7", Colors.blueGrey),
                    _buildButton("8", Colors.blueGrey),
                    _buildButton("9", Colors.blueGrey),
                    _buildButton("/", Colors.orange),
                  ],
                ),
                Row(
                  children: [
                    _buildButton("4", Colors.blueGrey),
                    _buildButton("5", Colors.blueGrey),
                    _buildButton("6", Colors.blueGrey),
                    _buildButton("*", Colors.orange),
                  ],
                ),
                Row(
                  children: [
                    _buildButton("1", Colors.blueGrey),
                    _buildButton("2", Colors.blueGrey),
                    _buildButton("3", Colors.blueGrey),
                    _buildButton("-", Colors.orange),
                  ],
                ),
                Row(
                  children: [
                    _buildButton("C", Colors.red),
                    _buildButton("0", Colors.blueGrey),
                    _buildButton("=", Colors.green),
                    _buildButton("+", Colors.orange),
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

어떻게 바뀌었나 확인해 보겠습니다.

figure 16

 

미적 감각이 없는 제가 봤을때는 적당해 보입니다. 하지만 역시 전혀 beautiful하지 않은 것 같습니다.

 

디자인은 더 이상 요청하지 않겠습니다.

 

이렇게 ChatGPT를 사용한 개발을 진행해 보았는데, 결론은 만족스러웠습니다.

 

몇 가지 염두에 두어야 할 사항은

 1. 질문을 잘해야 한다: 세세한 부분까지 고려되어야 하기 때문에 질문에 따라 원했던 결과에서 크게 벗어날 수 있고, 후속 코딩 요청에 모순이 발생할 수도 있습니다.

 2. 설계는 고려되지 않는다: 이는 당연한 이야기겠지만, 제가 요청하지 않는 이상 디자인 패턴 등을 사용하지는 않습니다. 모두 main.dart에서 코딩이 이루어졌습니다. 어쩌면 앱의 규모가 작기 때문일 수도 있으며, 여기서 기능이 더 추가되고 규모가 커진다면 GPT 스스로 소스를 나누고, 이상적인 설계를 적용할 가능성도 물론 있습니다.

 3. 미적 데이터는 부족하다: 저는 한 번만 요청하고 말았지만, 계속 반복해서 요청하다 보면 마음에 드는 디자인이 나올 수 있을지도 모릅니다.

 4. 개발 환경이 고려되지 않는다: 제가 따로 버전이나 IDE 등 개발 환경을 제공하지 않는 이상, GPT는 이를 고려하지 않거나 적당히 유추하여 답변을 내놓을 수밖에 없습니다. 미리 개발 환경을 제공하거나, 추후 발생하는 에러를 가지고 환경에 맞게 수정해야 하겠습니다.

 

종합적으로 판단했을 때 GPT는 훌륭한 개발 파트너가 맞는 것 같습니다.

 

특히 이런식의 전체적인 개발이 아닌, 국소적인 기능만을 요청해서 개발에 적용한다면 더욱 효율적으로 부릴 수 있겠지요.

 

이상 포스팅을 마치겠습니다.

 

감사합니다.

728x90
반응형