본문 바로가기
Mobile

[ Ionic ] 웹개발자가 만드는 Ionic 어플 - 2탄 (기초 구성 및 구현)

by 기저귀찬개발자 2020. 1. 31.

2019/12/02 - [Mobile] - [ Ionic ] 웹개발자가 만드는 Ionic 어플 - 1탄 (설치, 오픈 소스 활용)

2020/04/04 - [Mobile] - [ Ionic ] 웹개발자가 만드는 Ionic 어플 - 3탄 (배포)

2020/04/14 - [Mobile] - [ Ionic ] 웹개발자가 만드는 Ionic 어플 - 4탄 (배포 후 문제점)

 

https://play.google.com/store/apps/details?id=devjoo.ionic.widmarkapp

 

지금어때 - 실시간 음주 계산기, 술게임, 혈중 알콜 농도 계산, 음주 측정 - Google Play 앱

혈중 알콜 농도를 계산하여 건강한 음주 생활을 즐기세요. 나와 함께 같이 마신 사람들의 혈중 알콜 농도 또한 확인 가능합니다. 혈중 알콜 농도 계산과 함께 간단한 술게임으로 재밌는 음주 되세요

play.google.com

 

1탄에서는 설치 및 오픈 소스를 활용하는 법을 포스팅하고 꽤 많은 시간이 흘렀다. 

해당 앱개발을 하느라 포스팅을 미루고 있었는데 2탄을 올려본다.

개발하려는 앱에 대한 설명을 시작으로 포스팅을 하겠다.

 

앱 제목

본제 - 지금어때

부제 - 실시간 혈중 알콜 농도 계산기

 

앱 컨텐츠

소개 - 도로교통공단에서 제공되는 위드마크 공식을 사용하여 술자리에서 자신이 먹는 술의 양만큼 혈중 알콜 농도를 그래프로 가시화하여 보여주고 간단한 술게임들을 즐길 수 있게 한다.

 

목표는 1월 출시였는데 회사도 다니고 퇴사하고 하느라 생각보다는 오래걸렸다. 

만들어진 앱에 대한 소개를 하도록 하겠다.

 

탭구성으로 페이지는 3개의 탭으로 나눠져 있는데 하나씩 포스팅할 것이다.

 

1. 프로필

 - 기본 사용자에 대한 프로필을 저장하여 사용할 수 있도록 처리를 하였다.

 - 하단에는 무한 스크롤바를 넣어서 이전에 먹은 음주 데이터들을 확인할 수가 있다.

 

 - IonInfiniteScroll을 사용하여 무한 스크롤을 구현한 소스이다.

import { IonInfiniteScroll } from '@ionic/angular';

... 

  @ViewChild(IonInfiniteScroll,{static:false}) infiniteScroll: IonInfiniteScroll;
  eventSource = [];

...


    dataSet(dataId){

        var datas = JSON.parse(localStorage.getItem('data'+dataId));
        var members = JSON.parse(datas.memberData);
        var desc = '';

        members.forEach(function(member){
            desc += member.name+", ";
        },desc)

        var memname = ((members.length)>1)? members[0].name+', '+members[1].name:members[0].name;

        var startDate = new Date(datas.start);
        var theDate = startDate.getFullYear()+'/'+('0' + (startDate.getMonth()+1)).slice(-2)+'/'+('0' + startDate.getDate()).slice(-2);

        this.currentDataId = dataId;
        this.eventSource.push({
            id:dataId,
            title:memname+' 포함 총 '+(members.length)+'명',
            desc:desc,
            theDate:theDate
        });
    }

    loadData(event) {
      setTimeout(() => {

        event.target.complete();

        // App logic to determine if all data is loaded
        // and disable the infinite scroll
        for(let i=1; i<=5; i++){
          if (this.currentDataId > 1) {
              this.dataSet(this.currentDataId-1);

          }else{
              event.target.disabled = true;
              break;
          }
        }


      }, 500);
    }
    
  <ion-card *ngIf="eventSource.length > 0">
      <ion-list>
          <ion-item *ngFor="let event of eventSource">
              <ion-label class="label label-ios">{{event.id}} | {{ event.theDate }} | {{ event.title }} </ion-label>
              <button ion-button outline item-end (click)="goCalc(event.id)">자세히</button>
          </ion-item>
      </ion-list>
      <ion-infinite-scroll threshold="100px" (ionInfinite)="loadData($event)">
        <ion-infinite-scroll-content
          loadingSpinner="bubbles"
          loadingText="Loading more data...">
        </ion-infinite-scroll-content>
      </ion-infinite-scroll>
  </ion-card>

 

 

 

 

 

 

 

 - 자세히 버튼을 누르게 되면 나타나는 화면이다.

 - 도로교통공단의 음주 사고시 법적 책임에 대해 추가해두었다.

 

 

 

 - chart.js 와 chartjs-plugin-annotation을 사용하여 그래프를 출력할 수 있다.

 - chartjs-plugin-annotation은 설정값에 따라 그래프에 색칠하거나 라인으로 범위를 나타내 줄 수 있는 플러그인이다.

 - y축 범위에 따라 처벌기준이 달라지는 범위를 나타내준다.

import { Chart } from 'chart.js';
import * as ChartAnnotation from 'chartjs-plugin-annotation';

...


  ngOnInit(){
      Chart.pluginService.register([ChartAnnotation]);

      this.route.params.subscribe(
        data => {

          this.datas = JSON.parse(localStorage.getItem('data'+data.dataId))
          var startDate = new Date(this.datas.start);
          var endDate = new Date(this.datas.end);
          var datasets = [];
          var labels = [];

          this.title = (startDate.getMonth()+1)+'/'+startDate.getDate();
          this.title += ' ~ '+(endDate.getMonth()+1)+'/'+endDate.getDate();

          this.members = JSON.parse(this.datas.memberData);


          this.members.some(function(member){

            if(member.drinks.length == undefined || member.drinks.length <= 0) return false;

            this.drinksData.push(member.drinks);

            let color = this.setRandomColor();
            let startEatTime = member.drinks[0].eatTime - (member.drinks[0].eatTime%(30*60*1000)); //시간단위

            if(startEatTime < this.firstTime && this.firstTime!=0) this.firstTime = startEatTime;
            if(this.firstTime ==0) this.firstTime = startEatTime;

            let endEatTime = member.drinks[(member.drinks.length-1)].eatTime - (member.drinks[(member.drinks.length-1)].eatTime%(60*60*1000)) + (60*60*1000)

            if(endEatTime > this.endTime && this.endTime!=0) this.endTime = endEatTime;
            if(this.endTime ==0) this.endTime = endEatTime;

            let bacData = [];
            let time = this.firstTime;

            Object.setPrototypeOf(member, Member.prototype);
            let i=1;  //무조건 3번 검사후
            while(true){

              let bac = Number(member.getBAC(time));

              if(i>3 && bac<=0 && this.endTime < time){
                  bacData.push(0);
                  break;
              }

              i++;

              if(time > this.endTime) this.endTime = time;

              time += 30*60*1000 //30분씩 더하기

              bacData.push(bac);
            }

            datasets.push({
                label: member.name,
                backgroudColor:color,
                borderColor:color,
                fill:false,
                data: bacData
            });
        }, this);

        var time = this.firstTime;

        while(true){
          let timeDate = new Date(time);
          let label = timeDate.getHours() >= 10 ? (timeDate.getHours()) : '0'+ timeDate.getHours();

          label += ':'+(timeDate.getMinutes() >= 10 ? (timeDate.getMinutes()) : '0'+ timeDate.getMinutes());
          labels.push(label);

          if(this.endTime < time) break;
          time += 30*60*1000 //30분씩 더하기
        }


        this.bars = new Chart(this.memberChart.nativeElement, {
          type: 'line',
          data: {
            labels: labels,
            datasets: datasets
          },
          options: {
            scales: {
              yAxes: [{
                ticks: {
                  beginAtZero: true
                }
              }]
            },
            annotation: {
              annotations: [{
                  drawTime: 'beforeDatasetsDraw',
                  type: 'box',
                  id: 'a-box-1',
                  yScaleID: 'y-axis-0',
                  yMax: 0.08,
                  yMin:  0.03,
                  backgroundColor: 'rgba(255, 0, 0, 0.2)',
              },{
                  drawTime: 'beforeDatasetsDraw',
                  type: 'box',
                  id: 'a-box-2',
                  yScaleID: 'y-axis-0',
                  yMax: 0.2,
                  yMin:  0.08,
                  backgroundColor: 'rgba(255, 0, 0, 0.4)',
              },{
                  drawTime: 'beforeDatasetsDraw',
                  type: 'box',
                  id: 'a-box-3',
                  yScaleID: 'y-axis-0',
                  yMin:  0.2,
                  backgroundColor: 'rgba(255, 0, 0, 0.6)',
              }],
            }
          }
        });
        }

      )

  }

 

 

 

 

 

 

 

2. 혈중알콜농도

 - 음주량을 기입하는 화면이다. 

 - 인원을 선택한 뒤 하단의 카테고리에서 먹은 술의 종류를 클릭하면 데이터가 입력된다.

 

 

3. 술게임

 - 추후에도 게임을 추가할 수 있도록 리스트 형식으로 선택하게끔 만들었다.

 

3.1 Timebomb

 - 시간을 선택한 뒤 시작을 하면 폭탄이미지가 노출되고 시간이 지나면 터진 이미지로 변환된다.

 

 

 

위와 같이 Ionic 과 angular 를 통하여 앱을 만들었다. 출시하는 과정은 다음 포스팅에서 소개하도록 하겠다.

댓글