오늘 한 일
- Rust 공부(강의)
- 약알림 앱 약 등록 페이지 UI 구현
- 약알림 앱 메인 페이지 디자인 구현중
🦀 Rust 실습 - 영수증 관리 프로그램
// Project 1: Interactive bill manager
//
// User stories:
// * I want to add bills, including the name and amount owed.
// * I want to view existing bills.
// * I want to remove bills.
// * I want to edit existing bills.
// * I want to go back if I change my mind.
use std::io;
use std::io::{stdout, Write};
fn main() {
user_interactive();
}
//구조체 정의
struct Bill{
name: String,
owed: f64,
num: i32,
}
impl Bill{
fn new(name: &str, owed: f64, num: i32) -> Self{
Self{
name: name.to_owned(),
owed: owed,
num: num
}
}
}
//INTERACTIVE - 사용자 소통 로직
fn user_interactive() -> Result<(), io::Error> {
let mut bills: Vec<Bill> = vec![];
let mut BILL_NUMS = 0;
loop{
println!("1:영수증 추가, 2:영수증 조회, 3:영수증 삭제, 4:영수증 수정, 5:이전 작업 취소");
print!("어떤 작업을 하시겠어요? => ");
io::stdout().flush();
let user_input = get_input()?;
match user_input.as_str() {
"1" => add_bill(&mut bills, &mut BILL_NUMS),
"2" => read_bill(&mut bills),
"3" => delete_bill(&mut bills),
"4" => update_bill(&mut bills, &mut BILL_NUMS),
_ => println!("not impl yet"),
}
println!("");
}
}
// 사용자 입력값 받아서 Result<String>로 반환 함수
fn get_input() -> Result<String, io::Error> {
let mut buffer = String::new();
io::stdin().read_line(&mut buffer)?;
Ok(buffer.trim().to_owned())
}
//ADD 구현
fn add_bill(bills: &mut Vec<Bill>, BILL_NUMS: &mut i32) {
let mut result: Result<String, io::Error>;
let mut name = String::new();
let mut owed: f64 = 0.0;
print!("이름: ");
io::stdout().flush();
result = get_input();
match result{
Ok(buffer) => {
name = buffer;
}
Err(_) => {
println!("Add failed - IO issue");
}
}
print!("가격: ");
io::stdout().flush();
result = get_input();
match result{
Ok(buffer) => {
owed = buffer.parse().unwrap();
}
Err(_) => {
println!("Add failed - IO issue");
}
}
let bill = Bill::new(&name, owed, *BILL_NUMS);
*BILL_NUMS += 1;
bills.push(bill);
}
// READ 구현
fn read_bill(bills: &Vec<Bill>){
let mut result: Result<String, io::Error>;
let mut i: i32 = 0;
print!("이름: ");
io::stdout().flush();
result = get_input();
match result{
Ok(name) => {
for bill in bills{
if bill.name == name{
println!("[{:?}] #{:?} name: {:?}, owed: {:?}", i, bill.num, bill.name, bill.owed);
i+=1;
}
}
if i == 0 {
println!("name: {:?} bill NOT FOUND!", name);
}
}
Err(_) => {
println!("Read failed - IO issue");
}
}
}
// Delete 구현
fn delete_bill(bills: &mut Vec<Bill>){
let mut result: Result<String, io::Error>;
let mut bill_num = -1;
let mut index = 0;
print!("삭제할 영수증 번호: ");
io::stdout().flush();
result = get_input();
match result{
Ok(num) => {
bill_num = num.parse().unwrap();
for bill in &mut *bills{
if bill.num == bill_num{
bills.remove(index);
println!("Delete #{:?}", bill_num);
break;
}
index+=1;
}
if index == bills.len(){
println!("#{:?} does not exist", bill_num);
}
}
Err(_) => {
println!("Add failed - IO issue");
}
}
}
// UPDATE 구현
fn update_bill(bills: &mut Vec<Bill>, BILL_NUMS: &mut i32){
let mut result: Result<String, io::Error>;
let mut bill_num = -1;
let mut price:f64 = 0.0;
let mut index = 0;
let mut exist = false;
print!("바꿀 영수증 번호: ");
io::stdout().flush();
result = get_input();
match result{
Ok(num) => {
bill_num = num.parse().unwrap();
for bill in &mut *bills{
if bill.num == bill_num{
println!("#{:?} name: {:?}, owed: {:?}", bill.num, bill.name, bill.owed);
exist = true;
break;
}
index+=1;
}
if !exist{
println!("#{:?} does not exist", bill_num);
}
}
Err(_) => {
println!("Add failed - IO issue");
}
}
if exist{
print!("수정할 금액: ");
io::stdout().flush();
result = get_input();
match result{
Ok(prices) => {
price = prices.parse().unwrap();
let bill: Bill = Bill::new(
bills[index].name.as_str(),
price,
bills[index].num,
);
bills.remove(index);
bills.push(bill);
println!("=> owed: {:?}", price);
}
Err(_) => {
println!("Add failed - IO issue");
}
}
}
}
// Roll back
미구현
자체 피드백
add, remove, read의 재사용성을 고려했어야한다. - update에서 모두 사용되기 때문
add
/remove
/read
함수 내부에서 사용자 입력값을 받아서 핸들링
→ 입력 관리 buffer가함수
의 인자로 거쳐지지 않고 간단한 구조로 짜고자 했음⇒
함수
외부에서 사용자 입력값을 버퍼에 저장하고 인자값으로 넘겨주어 값을 핸들링했어야한다.
그 이유는 인자값을 받는 함수를 사용하면 사용자가 입력하지 않아도 내부적으로 관리할 때 그 로직이 필요하면 사용할 수 있게하기 위해서이다. → 수정은 귀찮으니 로직만 이렇게 생각해두자.Collection 구조로 vector를 선택했다.
→
HashMap
으로는 key의 충돌이 발생할 수 있다고 생각했기 때문⇒ key를
사람: String
이 아닌bill num: i32
으로 했다면 깔끔하게 정리됐을 것 같다.⇒ key가 사람 이름인게 추상화로는 옳지만 컴퓨터 내부 관리용으로 HashMap도 나쁘지 않은 것 같다.
그렇다고 vec보다 HashMap이 좋냐고 물어보면 나는 잘 모르겠다.
💊 약 등록 페이지 UI 구현
🎯 Button 색상 변경
: 기본적으로 theme을 쓴다면 default color는 android:colorAccent
라고 한다.
[case 1] Button Style이 없는 경우
→ android:backgroudTint = "colors/SOMETHING"
[case 2] Button Style을 설정해준 경우
→ 미해결
⇒ 버튼 UI로 만든 후 클릭시 상태 변화를 어떻게할지 생각만해도 머리아프다.
🎯 Row(LinearLayout-horizontal) 최대간격으로 만들기
[시도 1] LinearLayout gravity를 쓰는 경우
→ 못찾았다.
[시도 2] Flutter의 Extended와 같이 빈공간을 모두 차지할 위젯을 찾는다.
⇒ weight를 중간 Space 컴포넌트만 1로 설정함으로써 해결
[재욱님의 피드백] LinearLayout보단 ConstraintLayout으로 스크린의 상대적 위치에 따라 배치하는 것을 추천
⇒ Linear로 배치하는 경우 Linear에서 사용되는 컴포넌트-children-의 크기를 동적으로 핸들링하기가 힘들기 때문에
스크린의 크기가 달라질 때 예상치 못하게 위치가 깨질 수 있다.
=> 이 피드백을 고려해봤을 때, Linear는 ScrollView와 같이 명확하게 필요한 상황에서만 사용하는 게 좋을 것 같다.
🎯 Material Icon 리소스로 등록하기
: drawable > new > vector image > 검색 후 등록