Skip to content

it2810-webutvikling-h18-prosjekt-3-44 created by GitHub Classroom

Notifications You must be signed in to change notification settings

IT2810/it2810-webutvikling-h18-prosjekt-3-44

Repository files navigation

TODO Walk

TODO Walk er en app der man kan lage oppgaver med et antall skritt man har på seg før oppgaven skal være gjort. Når oppgaven er fullført kan man bekrefte at oppgaven er fullført og den blir da slettet.

Samarbeid og bruk av Git

Vi har vært en gruppe på 2 personer. Til å begynne med delte vi prosjektet inn i ulike deler og opprettet issues for disse med en kort beskrivelse. Noen a disse var å lage en mockup av appen, lage statiske layouter av ulike skjermbilder som senere kunne bli implementert, implementere AsyncStorage, navigasjon, implementere skritteller osv.

Til å begynne med opprettet vi en mockup. Etter å ha fått opp denne tok en person ansvar for å lage det statiske designet og sette i gang med testing, mens den andre fikk implementert navigasjon, satt opp asyncstorage og fant et bibliotek for bruk av skritteller og fikk implementert dette.

Selv om arbeidsoppgavene var vel definerte har prosjektet krevd tett samarbeid, der vi har utvekslet kunnskap og ideer om bibliotekene og teknologien vi har benyttet. Vi har også parprogrammert litt for å løse noen av de mer komplekse utfordringene. F.eks ved implementering av AsyncStorage.

Issues og commits

Hver issue som opprettes i Github har en egen ID. Commits som bidrar eller løser en spesiell issue har fått ID'n til issuen først i commit-meldingen. Mindre commits som ikke er koblet direkte til en issue på denne måten, har bare blitt commitet uten å være linket til en issue. F.eks oppdateringer av README og lignende.

Mockup

Etter at vi hadde en idé var det første vi gjorde å lage en mockup av hvordan designet kunne se ut. På den måten fikk vi en oversikt over hva som måtte gjøres. Vi kom frem til at vi hadde behov for to ulike skjermbilder.

Mockup

Venstre mockup viser det vi kaller ListView, en liste over oppgaver og hvor mange skritt som er igjen for hver oppgave. Man kan trykke på de ulike oppgavene for å endre dem eller opprette en ny ved å trykke på knappen i det nederste feltet. Da kommer man til skjermen i høyre mockup.

I høyre mockup ser man det vi kaller TaskDetailView. Her kan man opprette en ny oppgave eller endre en som allerede eksisterer, avhengig av hva man trykte på i ListView. Man kan legge til en tittel, antall skritt man har på seg før oppgaven skal være fullført og en beskrivelse. Dessuten kan man slette oppgaven eller nullstille antall skritt som er blitt gått for oppgaven.

Designet til den ferdige appen ble veldig lik mockupen, men med noen endringer både for ListView og TaskDetailView. Endringer på ListView var posisjonering av tekst og at det endelige designet inkluderer en knapp som lar brukeren trykke på at oppgaven er fullført. Noen endringer for TaskDetailView er at istedet for ikoner øverst for å nullstille skritt og fjerne en oppgave, så laget vi noen knapper med tekst nederst på skjermen.

Andre endringer som ikke ble med i den ferdige appen var at vi unnlot å implementere funksjonalitet for å nullstille skritt og å slette en oppgave før den er fullført.

Biblioteker

React Navigation

For å implementere en pen og enkel navigering mellom skjermene valgte vi å benytte oss av React Navigation fra https://reactnavigation.org/en/.

For å bruke dette biblioteket må man importere createStackNavigator. Dette er en funksjon som returnerer en React-komponent som kan vises. Denne tar inn et route configuration object og et valgfritt options object der man kan sette blant annet initielt navn på skjermbildet som vises.

import { createStackNavigator } from 'react-navigation';

Deretter kan man opprette et objekt av denne eller bare eksportere den direkte.

const RootStack = createStackNavigator(
	{
		Home: ListView,
		TaskDetailView: TaskDetailView,
	},
	{
		initialRouteName: 'Home',
	}
);

Videre kan man kan vise skjermen ved å kalle <RootStack /> i render.

De ulike skjermene får en referanse til en navigation-objekt som de kan bruke til å navigere til andre skjermer. F.eks slik:

this.props.navigation.navigate('Home')

Les mer om hvordan man kommer i gang med React Navigation her.

NativeBase

For å implementere en del komponenter som har med layout og input å gjøre, som fungerer til både Android og iOS, valgte vi å benytte oss av NativeBase fra https://nativebase.io

Dette biblioteket har mange ulike komponenter, men i vårt prosjekt var følgende komponenter aktuelle: Container, Content, Text, Footer, Button, List, ListItem, Card, CardItem, Body og Input

For å implementere NativeBase importerer man bare de komponentene man ønsker, og bruker de der de trengs. F.eks slik:

import { Card, CardItem, Body, Text } from 'native-base';

Noe man må være oppmerksom på er at dette biblioteket bruker noen egne fonts som må lastes inn asynkront før de blir forsøkt brukt. Dette løste vi ved å gi App en variabel loading som indikerer at den fortsatt laster. this.state = { loading: true };.

Fontene lastes inn asynkront og loading settes til false når de er lastet:

async componentWillMount() {
    await Expo.Font.loadAsync({
      Roboto: require("native-base/Fonts/Roboto.ttf"),
      Roboto_medium: require("native-base/Fonts/Roboto_medium.ttf")
    });
    this.setState({ loading: false });
  }

I render blir ikke fontene forsøkt brukt før de er lastet inn:

render() {
  if (this.state.loading) {
    return <Expo.AppLoading />;
  }

  return (
    <RootStack />
  );
}

Les mer om hvordan man kommer i gang med NativeBase her.

AsyncStorage

AsyncStorage er et enkelt bibliotek for asynkron, permanent lagring av tilstand, slik at man kan lagre data selv når appen avsluttes.

På iOS er AsyncStorage implementert med iOS-spesifikk kode som lagrer små verdier i en serialisert key-value storage og større verdier i separate filer. På Android brukes enten RocksDB eller SQLite, avhengig av hva som er tilgjengelig.

Alle funksjoner i AsyncStorage API returnerer et Promise objekt.

AsyncStorage importeres på følgende måte:

import { AsyncStorage } from "react-native"

Eksempel på lagring av data:

_lagreData = async () => {
  try {
    await AsyncStorage.setItem('@MySuperStore:key', 'Data jeg ønsker å lagre');
  } catch (error) {
    // Noe gikk galt ved lagring av data
  }
}

Eksempel på henting av data:

_hentData = async () => {
  try {
    const value = await AsyncStorage.getItem('TASKS');
    if (value !== null) {
      console.log(value);
    }
   } catch (error) {
     // Noe gikk galt ved henting av data
   }
}

Les mer om hvordan man kommer i gang med AsyncStorage her.

Pedometer

Pedometer er et bibliotek fra Expo som brukes for å kommunisere med mobilens skritteller. Biblioteket fungerer for både Android og iOS og benytter seg av API til User Core Motion for iOS og Google Fit for Android.

Antall skritt hentes ut ved at man sender med en funksjon som callback når registrere seg på tjenesten. Callbackfunksjonen kalles hver gang Expo Pedometer oppdateres fra User Core Motion eller Google Fit.

subscribe = () => {                                                                                                                                                                                                                                    
  this._subscription = Pedometer.watchStepCount(result => {                                                                                                                                                                                            
    if (result.steps === parseInt(result.steps, 10)) {                                                                                                                                                                                                 
      this.updateSteps(result.steps);                                                                                                                                                                                                                  
    }                                                                                                                                                                                                                                                  
  });                                                                                                                                                                                                                                                  
};

Testing

For å teste appen har vi brukt Jest.

I utils-test.js tester vi utils-funksjonen stepsNotEqual, en funksjon som returnerer true dersom dens to argumenter er ulik, og false dersom de er like.

Testene kjøres med jest i terminalen. Noe vi har gjort ved jevne mellomrom for å kontrollere at skritt regnes ut som de skal.

Vi har dessuten gjort utallige forsøk på å få til snapshot-testing og testing av AsyncStorage ved bruk av en mock fra https://github.com/devmetal/mock-async-storage, men den samme feilmeldingen fra Jest har gjort at vi ikke har kommet noen vei. Flere grupper har hatt problemer med den samme feilen og vi har ikke hørt at noen har funnet ut hva feilmeldingen skyldes.

Vi har forsøkt å teste snapshots på følgende måte:

import React from 'react';
import ListView from '../components/ListView';
import { Container, Content, Text, Footer, Button } from 'native-base';

import renderer from 'react-test-renderer';

jest.mock("native-base", () => {});

test('renders correctly', () => {
  const tree = renderer.create(<ListView />).toJSON();
  expect(tree).toMatchSnapshot();
});

Vi har forsøkt å lagring og henting med AsyncStorage på følgende måte:

import 'react-native';
import MockAsyncStorage from 'mock-async-storage'
import React from 'react';
import ListView from '../components/ListView';

// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';

const mock = () => {
  const mockImpl = new MockAsyncStorage()
  jest.mock('AsyncStorage', () => mockImpl)
}

mock();

jest.mock("native-base", () => {});

import { AsyncStorage as storage } from 'react-native'

it('renders correctly', () => {
  const tree = renderer.create(
    <ListView />
  );
});

it('Mock Async Storage working', async () => {
  await storage.setItem('myKey', 'myValue')
  const value = await storage.getItem('myKey')
  expect(value).toBe('myValue')
})

Jest gir en feilmelding om at den ikke klarer finne komponenter som rendres i komponenter vi forsøker å teste. Vi har forsøkt å mocke disse komponentene, men heller ikke det fungerte. Feilmeldingen ser dere under.

Feilmelding

Det kunne vært interessant å se om Enzyme var enklere å jobbe med, eller om problemene med Jest har en enkel forklaring.

About

it2810-webutvikling-h18-prosjekt-3-44 created by GitHub Classroom

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published