Realizace projektu EPIrozvrh a popis kódu

Z Kiwiki
Verzia z 21:22, 8. september 2013, ktorú vytvoril Tonda (diskusia | príspevky) (Vytvorená stránka „{{Praca_uvod|5|Rozšíření informačního systému EPI, s.r.o. na mobilní platformu Android|Analýza platformy Android|Analýza informačního systému rozvrhu a mož...“)
(rozdiel) ← Staršia verzia | Aktuálna úprava (rozdiel) | Novšia verzia → (rozdiel)
Skočit na navigaci Skočit na vyhledávání

Vnitřní struktura aplikace EPI rozvrh se skládá ze dvou balíčků a to z cz.sajboch.epi_main a cz.sajboch.epi_timetable, dále jen epi_timetable, jenž reprezentuje balíček pro zobrazení školního rozvrhu. V následující části jsou popisovány pouze balíčky vytvořené v rámci této práce.


Rozdělení tříd do balíčků zajišťuje snadnou modifikaci aplikace a případné rozšíření o další funkce. Hlavní balíček cz.sajboch.epi_main se skládá ze šesti tříd: MainActivity, LoginActivity, AboutActivity, OnlineRecords, TimetableActivity a Settings, viz schéma č. 6.


Súbor:Diagram třídy cz.sajboch.epi main

Schéma č. 6: Diagram třídy cz.sajboch.epi_main

Zdroj: vlastní.


Jak je patrné ze schématu č. 6, třída MainActivity je potomkem systémové třídy android.app.Activity, což ji tvoří spustitelnou. Třída MainActivity se spouští po spuštění aplikace. Její hlavní rolí je zobrazení ovládacího menu, jež obsahuje tlačítka. Grafické zobrazení je vytvořeno na základě XML souboru activity_main.xml. Po spuštění této třídy dochází k ověření přihlašovacích údajů.


Následující obrázek je náhledem menu aplikace, jenž je vytvořeno na základě třídy MainActivity. Obrázek byl pořízen na mobilním zařízení Samsung Galaxy mini.


Súbor:Hlavní menu zařízení, Samsung Galaxy mini

Obrázek č. 12: Hlavní menu zařízení, Samsung Galaxy mini

Zdroj: vlastní


Třída Settings je potomkem třídy android.preference.PreferenceActivity a slouží k zobrazení a modifikaci nastavení aplikace a uchovává přihlašovací údaje, datum poslední aktualizace, způsob aktualizace atd.


Balíček epi_timetable tvoří rozvrh hodin a jeho funkce. Skládá se z několika dalších balíčků, kde každý z těchto balíčku má specifický význam.


Seznam balíčků epi_timetable:

  • cz.sajboch.epi_timetable.communications dále jen communications,
  • cz.sajboch.epi_timetable.lib dále jen lib,
  • cz.sajboch.epi_timetable.popups dále jen popups,
  • cz.sajboch.epi_timetable.timetable dále jen timetable,
  • cz.sajboch.epi_timetable.widgets dále jen widgets.

V následujících kapitolách budou popsány jednotlivé balíčky, jejich funkce, využití a způsob, jakým se používají.


Balíček communications

Balíček communications poskytuje aplikaci komunikační protokoly pro připojení ke školnímu serveru a následné uložení stažených dat. Skládá se ze sedmi tříd, které jsou mezi sebou závislé. Tyto závislosti jsou viditelné na následujícím schématu č. 7.


Súbor:Diagram třídy communications Schéma č. 7: Diagram třídy communications

Zdroj: vlastní


Třída Update slouží pro spuštění procesu aktualizace. Proces aktualizace probíhá tak, že se stáhnou data rozvrhu hodin ze školního serveru a následně se uloží do lokální databáze a souborů v mobilním zařízení. Stažení dat zajišťuje třída NetworkConnect běžící paralelně s hlavním vláknem programu. Paralelní běh zajišťuje rodičovský prvek AsyncTask, který vytvoří nové vlákno. Komunikace mezi těmito vlákny zajišťuje rozhranní AsyncTaskCompleteListener, jež třída Update implementuje.


Vložení dat do databáze zajišťuje třída DataToDatabase. Pro načtení dat z databáze se používá třída DataFromDatabase. Obě třídy jsou potomkem Database a ta je potomkem SQLiteOpenHelper. Uložení a načtení dat ze souboru zajišťuje třída SaveListToFile.


Aktualizace

Aktualizace rozvrhu hodin jsou buď automatické, nebo ruční. To znamená, že aplikace může sama aktualizovat data rozvrhu hodin po určitém časovém intervalu. Časový interval určuje nastavení uživatele, kde uživatel má možnost zvolit z několika předem určených časových intervalů.


Při vytvoření instance třídy Update se zavolá konstruktor, ve kterém dojde k ověření, zda je databáze rozvrhu hodin aktuální vzhledem k nastavení intervalu aktualizací.Do proměnné autoUpdate datového typu boolean se uloží logická hodnota 1, neboli true, pokud jsou povoleny automatické aktualizace. Pokud povoleny nejsou, uloží se logická hodnota 0, tedy false. Výchozím nastavením je logická hodnota true. Tuto hodnotu si může uživatel změnit v nastavení zaškrtnutím políčka „Automatické aktualizace“.


Zda je rozvrh hodin zastaralý zjistí metoda isOutDate(). Zjistí to tak, že porovná datum poslední aktualizace s aktuálním datem. Pokud je rozdíl větší než sedm dnů, metoda vyhodnotí rozvrh jako zastaralý a vrátí hodnotu true, v opačném případě vrátí hodnotu false. Rozdíl sedm dnů, tedy jeden týden, lze přenastavit na jinou hodnotu v nastavení aplikace.


Konstruktor třídy ověřující, zda bude spuštěná automatická aktualizace:

public Update(Context context){
if (autoUpdate && this.isOutDate ()) {
this.start();
}
}

V případě, je-li podmínka splněná, tedy jsou zapnuty automatické aktualizace a zároveň je interní databáze zastaralá, spustí se metoda start() třídy Update. Ta zjistí, zda již existuje interní databáze. Pokud existuje, bude zaktualizována pouze část rozvrhu hodin, a to od data provádění aktualizace do konce školního roku. Pokud interní databáze neexistuje, vytvoří se a zaktualizuje se rozvrh hodin od začátku až po konec školního roku. Následující kód popisuje část metody start() rozhodující v jakém rozsahu bude interní databáze aktualizována.

Rozsah aktualizace interní databáze:

if (db.isTimetableTable()) {
this.updateFrom = MyDate.getDate();db.deleteOlderFromTimetable(
MyDate.getZacatekSkolnihoRoku());
 } else {
this.updateFrom = MyDate.getZacatekSkolnihoRoku();
}

Aktualizace může být spuštěna ručně, dojde-li k zavolání metody start() pomocí vytvořené instance této třídy.


Stahování dat

Platforma Android nemůže přímo přistupovat k databázi MYSQL, proto byla vytvořena další vrstva zabezpečující aplikaci přístup k datům. Tato vrstva je vytvořena pomocí PHP skriptu. PHP skript se obsluhuje HTTP požadavky typu POST. Na základě odeslaného požadavku vytáhne z databáze data, která pak zobrazí ve formě prostého textu formátovaného metodou JSON, viz kapitola 2.2.2. Na straně aplikace se o odeslání požadavku a zpracování výsledku stará metoda NetworkConnect.


Operační systém Android nedovoluje provádět operace trvající delší dobu ve vlákně UI. Stahování dat se tedy provádí v jiném vlákně běžícím paralelně s vláknem UI, ale paralelně běžící vlákno nemůže přímo přistupovat k vizuálním prvkům a jakkoliv je editovat. Pokud je potřeba například aktualizovat vizuální prvek z paralelně běžícího vlákna, může se použít systémová třída android.os.AsyncTask, dále jen AsyncTask, a ta zajistí paralelní běh vlákna a průběžné aktualizace vizuálních prvků.


NetworkConnect je potomkem AsyncTask, což ji činí spustitelnou v paralelně běžícím vlákně a dovoluje jí aktualizovat vizuální prvek. Z rodičovské třídy se převezmou metody doInBackground( Params … ) a onPostExecute( result[] … ), které je třeba v této třídě implementovat.


Třída NetworkConnect a zděděné metody od rodičovské třídy:

public class NetworkConnect extends AsyncTask<Void, Void, String[]> {

@Override
protected String[] doInBackground(Void... params) {
String[] result;

return result;
}
@Override
protected void onPostExecute(String[] result) {
callback.onTaskComplete(result);

}
}

Zděděná metoda doInBackground(Void… params) se spouští již v novém vlákně, kde se odesílají požadavky serveru, jejichž výsledky se stahují ve formě textu. Jeden požadavek serveru může obsahovat více parametrů, a proto jsou jednotlivé požadavky vkládány do kolekce, která se odesílá jakožto jeden požadavek. Jednotlivé parametry požadavku obsahují dvojici klíč:hodnota a ukládají se proto do proměnné datového typu NameValuePair, který je uzpůsoben k ukládání těchto hodnot.


Díky sofistikovanému využití metody doInBackground(Void… params) je možné odeslat více požadavků sériově. To probíhá tak, že se odešle požadavek, stáhne se výsledek odeslaného požadavku, který se uloží do pole datového typu String. Pak se odešle další požadavek, jehož výsledek se zase uloží do pole. Tento děj se opakuje tolikrát, kolik je požadavků. Po stažení posledního výsledku se ukončí vlákno a pole výsledků se odešle metodě onPostExecute(String[] result), která již běží v hlavním vlákně UI.


Metoda onPostExecute(String[] result) pole výsledků žádným způsobem nezpracovává, pouze jej přeposílá dále, pomocí rozhraní AsyncTaskCompleteListener, jehož instance byla převzata při volání konstruktoru třídy NetworkConnect. Rozhraní poskytuje metodu zpětného volání, která se provede v místě vytvoření konstruktoru NetworkConnect, kde je umístěna.


Způsob komunikace třídy NetworkConnect je založený na pokročilých návrhových vzorech. [9, s. 286]

Konstruktor třídy NetworkConnect:
public NetworkConnect(AsyncTaskCompleteListener<String> cb) {
this.callback = cb;
}

Způsob použití třídy NetworkConnect je velmi jednoduchý. Nejprve se vytvoří instance třídy, poté se zadají jednotlivé požadavky pro stažení dat pomocí níže zmíněných metod a v poslední řadě se zavolá metoda execute() spouštějící paralelní vlákno, které vykoná veškeré požadavky v metodě doInBackground(Void… params). Pro opakované použití třídy je potřeba vytvořit novou instanci.


Metody třídy NetworkConnect pro nastavení požadavků:

  • public void setList()- nastaví požadavky pro stažení seznamu učitelů, místností a studijních kruhů,
  • public void setNameValuePair(List<NameValuePair> nameVP) - nastaví libovolný požadavek,
  • public void setUcitel(String u, String dateFrom, String dateTo) - stáhne data rozvrhu hodin pro učitele v časovém intervalu {dateFrom, dateTo},
  • public void setClass(String t, String dateFrom, String dateTo) - stáhne data rozvrhu hodin pro studijní kruh v časovém intervalu {dateFrom, dateTo},
  • public void setClass(String m, String dateFrom, String dateTo) - stáhne data rozvrhu hodin pro místnost v časovém intervalu {dateFrom, dateTo}.

Ukládání dat

Aplikace ukládá data rozvrhu hodin a řídící data, které reprezentují seznam učitelů, místností a studijních kruhů. Data rozvrhu hodin a řídící data se ukládají rozdílným způsobem. Řídící data se ukládají v serializované podobě do souboru, kdežto data rozvrhu hodin se ukládají do lokální databáze. Jedná se o datové soubory, které byly popsány v kapitole 4.2.2.

Ukládání dat do databáze

Pro uložení dat získaných ze školního serveru je použita interní databáze SQLite, kterou poskytuje platforma Android. Databázi reprezentují třídy DataToDatabase a DataFromDatabase, které jsou potomky třídy Database. Database obsahuje strukturu databáze a to znamená, že určuje název databáze, názvy tabulek, názvy sloupců a jejich datové typy. Také samotnou databázi vytváří, což zajišťuje rodičovský prvek android.database.sqlite.SQLiteOpenHelper.


Vkládání dat do databáze zajišťuje třída DataToDatabase využívající funkce třídy android.database.sqlite.SQLiteDatabase pomocí její instance, díky které je možné provádět SQL dotazy. Také lze pomocí této třídy smazat celou databázi nebo pouze její část.


Data se do databáze vkládají prostřednictvím datového typu TimetableData uchovávající data datového typu CellData reprezentující jeden záznam v databázi.


Využití metod třídy DataToDatabase:

  • public void updateTimetableDB(TimetableData td) - smaže data z databáze, které jsou novější než nejstarší datum vkládaných prvků a následně vloží nové data v proměnné db,
  • public void updateTimetableDB(TimetableData td, String uFrom) - smaže data z databáze, které jsou novější než datum nacházející se v proměnné uFrom, a následně vloží do databáze data z proměnné db,
  • public void deleteOlderFromTimetable(String olderThan) - smaže data z databáze, starší než datum v proměnné olderThen,
  • public void deleteDb() - smaže celou databázi,
  • public void addData(TimetableData td) - přidá do databáze data z proměnné td a zachová předcházející data uložená v databázi.

Načtení dat z databáze zajišťuje třída DataFromDatabase, která pracuje na stejném principu jako třída DataToDatabase, ale nemá zapisovací práva. Díky tomu, že existují třídy pro čtení a zapisování do databáze zvlášť, je zajištěna určitá bezpečnost dat. Také se tím předchází nechtěnému smazání dat z databáze.


Využití metod třídy DataFromDatabase:

  • public TimetableData getData(String week), načte data z databáze za období jednoho týdne, proměnná week obsahuje datum začátku týdne,
  • public TimetableData getOneDayData(String day, int time), načte data z databáze ze dne, jehož datum se nachází v proměnné day a zároveň čas uložený v proměnné time než čas začátku hodiny.

Ukládání dat do souboru

Do souboru se ukládají seznamy učitelů, studijních kruhů a místností. Datovým typem takto ukládaných dat je List. Podrobnější popis je v kapitole 4.2.2. Pro ukládání dat je použita třída SaveListToFile, kde jsou využity principy pro práci se soubory v kombinaci s operačním systémem Android. Třída obsahuje řetězcové konstanty, které obsahují názvy souborů. Třída SaveListToFile pracuje s daty jako s objekty a také je tak ukládá do souboru.


Řetězcové konstanty uchovávající název souboru:

  • public final static String TEACHER_LIST_FILE = "timetable_t_list.dat",
  • public final static String ROOM_LIST_FILE = "timetable_r_list.dat",
  • public final static String CLASS_LIST_FILE = "timetable_c_list.dat".

Ukládání dat zajišťuje writeListToFile(List<String> list, String filename) přebírající dva parametry a to list datového typu List a název souboru filename datového typu String. Jako parametr filename může být použita některá z proměnných této třídy, avšak nemusí. Zavoláním této metody dojde k serializaci listu a jeho následné uložení do souboru s názvem, který byl předán jako parametr filename.


Volání statické metody writeListToFile():

  • SaveListToFile.writeListToFile(list,SaveListToFile.TEACHER_LIST_FILE)

Načtení jednotlivých dat ze souboru zajišťuje statická metoda List<String> loadListFromFile(String filename). Metoda přebírá jeden parametr filename určující název souboru, ze kterého se mají načíst data. Při zavolání metody dojde k načtení dat ze souboru a na základě těchto dat se vytvoří nový objekt datového typu Object. Ten se následně převede na datový typ List. Návratová hodnota je datového typu List a obsahuje načtená, jinak neupravená, data.


Volání statické metody loadListFromFile():

  • SaveListToFile.loadListFromFile(SaveListToFile.ROOM_LIST_FILE)

Obě zmiňované metody pracují na principu ukládání a načítání dat formou objektu. [8, s. 289]


Balíček lib

Veškerý běh aplikace, který není vidět a nemá co dočinění s vnější komunikací, zabezpečují třídy tohoto balíčku a ten reprezentuje celou datovou strukturu rozvrhu hodin, jenž je velmi komplikovaná.


Súbor:Diagram balíčku lib Schéma č. 8: Diagram balíčku lib Zdroj: vlastní


Předcházející schéma balíčku lib se skládá ze šesti tříd. MyDate zpracovává datum a provádí s ním různé operace. Třída UpdateThread zajišťuje zpracování stažených dat v paralelně běžícím vlákně. To je umožněno díky rodičovskému prvku android.os.AsyncTask. Třída MyJson slouží ke zpracování dat, která byla stažena. Stažená data jsou poté uložena do proměnné datového typu CellData reprezentující jednu buňku v rozvrhu hodin.

Třída TimetableData zpracovává a eviduje data datového typu CellData. V poslední řadě stojí třída LoginVerification, která slouží k ověření, zda proběhlo úspěšné přihlášení. Pracuje s instancí NetworkConnect a rozšiřuje ji rozhraní AsyncTaskCompleteListener.


Zpracování stažených dat

Data ze školního serveru jsou stažena ve formě prostého textu s formátováním JSON, což je popsáno v kapitole 2.2.2. Takto formátovaná data nejsou vhodná pro další zpracování aplikací. Aplikace má proto vlastní datovou strukturu pro stažená data, do které jsou stažená data zapracována.


Datovou strukturu reprezentují třídy CellData a TimetableData. Tato datová struktura je pouze jakýmsi rozhraním mezi staženými daty, databází a vykreslením rozvrhu hodin.


Rozvrh hodin se vizuálně skládá z řádků a sloupců. V místě protnutí určitého řádku a sloupce, tedy v buňce, může být umístěno více informačních buněk. Informační buňkou se myslí grafická buňka nesoucí informace o dané vyučovací hodině.


Základním kamenem této struktury je třída CellData, ve které jsou uložena data reprezentující jednu informační buňku v rozvrhu hodin.


Proměnné třídy CellData:

  • numberOfDay - obsahuje hodnoty od nuly do šesti kde nula symbolizuje pondělí, číslo jedna úterý, číslo dva středu, atd.,
  • color - hexadecimální číselný údaj reprezentující barvu buňky,
  • date - datum dne ke kterému se vztahují údaje,
  • endTime - čas konce vyučovací hodiny definovaný v standardním unixovém čase,
  • hour - číslo vyučovací hodiny,
  • hours - počet hodin jdoucích bezprostředně za sebou,
  • subject - celý název vyučovacího předmětu,
  • group - číslo nebo název skupiny, pro kterou jsou data určeny,
  • studyCircle - název studijního kruhu,
  • time - čas začátku hodiny v milisekundách,
  • schoolRoom - název učebny,
  • teacher - celé příjmení a tituly učitele,
  • teachers - seznam učitelů pro které platí tyto data,
  • studyCircles - seznam studijních kruhů pro které platí tyto data,
  • abbSubject - zkratka předmětu,
  • abbSchoolroom - zkratka učebny,
  • abbTeacher - zkratka učitele.

Jelikož jsou veškeré proměnné privátní, existují metody pro jejich správu. Pro každou proměnnou existují minimálně dvě metody pro správu. Jedna metoda proměnnou nastavuje na jinou hodnotu a druhá metoda získává aktuální nastavení proměnné. Metod pro práci s proměnnými je mnoho, a proto není možné je zde všechny zmínit.


Některé z metod pro práci s proměnnými:

  • setSubject(String value) - nastaví proměnnou subject na hodnotu value,
  • setTeacher(String value) - nastaví proměnnou teacher na hodnotu value,
  • getSubject() - vrací hodnotu textového řetězce proměnné subject,
  • getTeacher() - vrací hodnotu textového řetězce proměnné teacher.

Jak již bylo zmíněno, jeden objekt CellData obsahuje data pouze jedné informační buňky v rozvrhu hodin. Stažená data, která se mají uložit do databáze, obsahují však více takových buněk. Proto existuje třída TimetableData, jež spravuje jednotlivé objekty CellData. Spravuje je tak, že je jednotlivě ukládá do objektu List, tím tvoří seznam objektů CellData.


Objekty se vkládají do zásobníku jeden za druhým a první objekt je v zásobníku úplně naspodu. Další objekty se skládají nad první v pořadí, v jakém jsou vkládány. Při načítání jednotlivých dat se musí brát shora dolů, tedy od posledního k prvnímu.


Metody TimetableData:

  • addData(CellData), přidá objekt CellData do seznamu,
  • getFirstDate(), vrátí objekt CellData s nejmenším datem,
  • getSize(), vrátí počet prvků v seznamu,
  • getCell(), vrátí poslední objekt CellData, poté jej zahodí,
  • hasCell(), zjistí, je-li v seznamu nějaký objekt,
  • getHour(int hodina), je statická metoda, kterou lze použít bez vytvoření instance, vrací čas začátku a konce vyučovací hodiny v milisekundách předané v parametru hodina.

Práce s datem

Aplikace rozvrhu hodin velmi často pracuje s datem, ať už při vykreslení rozvrhu hodin nebo uložení dat do databáze. Dá se tedy říct, že práce s datem hraje v aplikaci neodmyslitelnou roli a proto byla vytvořena samostatná třída MyDate obsahující metody ulehčující práci s datem. MyDate využívají veškeré balíčky aplikace rozvrhu hodin.


Všechny metody třídy MyDate jsou statické, lze k nim tedy přistupovat bez nutnosti vytvářet instanci třídy. Obsahuje více než dvacet metod, které se využívají zejména pro zjištění aktuálního dne v týdnu, čísla dne, zjištění data následujícího či předcházejícího dne, zjištění data pondělku v minulém či následujícím týdnu a podobně.


Ukázka některých metod třídy MyDate:

  • getEndOfSchollYear() - vrací textový řetězec s datem konce školního roku,
  • getStartOfSchoolYear() - vrací textový řetězec s datem začátku školního roku,
  • getMonday(String week) - přebírá datum některého dne v týdnu a vrací textová řetězec s datem pondělku v daném týdnu,
  • getNumberOfDay(String datum) - vrací číslo dne v týdnu, přičemž pondělí je 0 a neděle 6,
  • getNumberOfWeek(String date) - přebírá parametr date na jehož základě vrací číslo týdne v roce.

Ověření přihlašovacích údajů

Ověření přihlašovacích údajů zajišťuje třída LoginVerification, rozšiřuje ji rozhraní AsyncTaskCompleteListener a obsahuje instanci třídy NetworkConnect, jenž je popsaná v kapitole 5.1.2. NetworkConnect zajišťuje možnost odeslání přihlašovacích údajů školnímu severu, který ověří, zda jsou přihlašovací údaje správné. Pokud školní server vyhodnotí přihlašovací údaje jako správné, vrátí textový řetězec s hodnotou true. Vyhodnotí-li je jako nesprávné, vrátí textový řetězec s hodnotou false.


Aplikace přijatá data vyhodnotí v metodě onTaskComplete(String[] result), která je zavolána po stažení dat na základě požadavku. Vyhodnotí je tak, že ověří, zda na základě odeslaných přihlašovacích údajů serveru byl obdržen textový řetězec true. Pokud byl obdržen, tak se uloží přihlašovací údaje a stav přihlášení po dobu aktuálního školního roku. Po vypršení lhůty, se uživatel musí přihlásit znovu. Neobsahuje-li přijatý řetězec hodnotu true, není proces přihlášení úspěšný.


LoginVerification obsahuje vlastní rozhraní LoggedListener jehož metoda zpětného volání onLogged(boolean logged) je zavolána po ověření přihlašovacích údajů. Pokud bylo ověření přihlašovacích údajů kladné, je metodě předán parametr true. V opačném případě je předán parametr false.


Přihlašovací údaje jsou předány metodě verify(), která odešle přihlašovací údaje školnímu serveru. Odeslání přihlašovacích údajů probíhá pomocí instance třídy NetworkConnect.


Vnitřní struktura metody verify():

public void verify(String login, String password, String kontext) {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("login", login));
nameValuePairs.add(new BasicNameValuePair("pass", password));
nameValuePairs.add(new BasicNameValuePair("kontext", kontext));
nc.setNameValuePair(nameValuePairs);
nc.setPage("login.php");
if (NetworkConnect.isConnection(context))
nc.execute();
}

Metoda verify() přebírá tři parametry login, password a kontext. Těmto parametrům se přidělí klíčová hodnota definující jednotlivý parametr. Parametry jsou pak odeslány školnímu serveru pomocí instance třídy NetworkConnect za předpokladu, že je zařízení připojeno k síti internet.


Balíček timetable

Zobrazení rozvrhu hodin a správné zařazení stažených dat do jednotlivých buněk zajišťuje právě tento balíček. Tvoří jej pouze třídy, které zpracovaná data ve formě objektu TimetableData, zobrazí tak, aby jim uživatel porozuměl.


Súbor:Diagram balíčku timetable

Schéma č. 9: Diagram balíčku timetable

Zdroj: vlastní


Na schématu č. 9 jsou závislosti jednotlivých tříd v rámci tohoto balíčku i mimo něj. V následující části bude stručný popis jednotlivých tříd v rámci balíčku.


Jak lze vidět na schématu č. 9 třída CellView je potomkem systémové třídy android.widget.LinerLayout. Slouží k vykreslení jedné buňky obsahující data rozvrhu hodin.


Třída TimetableView je potomkem systémové třídy FrameLayout, implementuje rozhraní AsyncTaskCompleteListener z balíčku communications a vykresluje rozvrh hodin. Data rozvrhu hodin dokáže sama získat z databáze nebo ze školního serveru za pomoci zmiňované implementace. Vykreslení rozvrhu je závislé na typu dat, tedy jedná-li se o data učitele, místnosti nebo studijního kruhu. K tomu slouží výčtový typ TimetableTyp určující, jakým způsobem budou data v rozvrhu hodin zobrazeny.


Zobrazení rozvrhu hodin má v režii třída TimetableActivity, která je zároveň spouštěcí třídou rozvrhu hodin. To znamená, že po kliknutí na položku rozvrh hodin v menu aplikace se tato třída spustí a zobrazí rozvrh hodin. TimetableActivity implementuje řadu rozhraní, která slouží jako komunikační most mezi rozvrhem a uživatelem.


Princip vykreslení rozvrhu hodin

Vytvoření rozvrhu hodin probíhá ve dvou fázích. První fází je inicializace a zobrazení prázdné tabulky rozvrhu hodin. Tabulka rozvrhu hodin je sestavena ze základních vizuálních prvků, které poskytuje platforma Android a vytvořena programově, není tedy využito XML návrhu. Vnoření jednotlivých vizuálních prvků je na schématu č. 10.


Súbor:Způsob vnoření vizuálních prvků třídy TimetableView

Schéma č. 10: Způsob vnoření vizuálních prvků třídy TimetableView

Zdroj: vlastní

Tabulka rozvrhu hodin je postavena na vizuálním prvku FrameLayout, který vyplňuje celou dostupnou plochu obrazovky. Následuje prvek ScrollView1 zajišťující posouvání rozvrhu hodin ve vertikálním směru za předpokladu, že má tabulka rozvrhu hodin větší výšku než je výška obrazovky. Prvek ScrollView1 může obsahovat pouze jeden prvek. Proto obsahuje horizontální prvek LinearLayout obsahující dva prvky. Levým prvkem je TableLayout, jež obsahuje řádky tabulky pro zobrazení dnů. Pravým prvkem je ScrollView2 zajišťující posouvání rozvrhu hodin v horizontálním směru, avšak pouze pokud je tabulka rozvrhu hodin širší než šířka obrazovky.


Při posouvání v horizontálním směru se tedy neposouvá prvek TableLayout1, ale posouvá se pouze obsah ScrollView2, což je prvek TableLayout2 obsahující řádky tabulky rozvrhu hodin, které reprezentuje prvek LinerLayout3 orientovaný vertikálně. LinearLayout3 reprezentuje jednu buňku rozvrhu hodin obsahující prvky TextView2, kde jsou umístěna data.


Ve druhé fázi je rozvrh hodin naplněn hodnotami a poté je upravena velikost řádků. Tabulka je také naplněna daty jednotlivých dnů v týdnu. Princip rozložení dat v tabulce rozvrhu hodin je na následujícím obrázku.


Súbor:Rozložení dat tabulky rozvrhu hodin

Obrázek č. 13: Rozložení dat tabulky rozvrhu hodin

Zdroj: vlastní


Buňka rozvrhu hodin může obsahovat více informačních buněk. To proto, že jedna vyučovací hodina může být vyučována více učiteli, ve stejné místnosti může být více studijních kruhů, studijní kruh je rozdělen na skupiny, atd.

Každá informační buňka obsažená v jedné buňce tabulky rozvrhu hodin tedy charakterizuje výuku ve stejný časový okamžik a pro různé účastníky.


Ovládání rozvrhu hodin zajišťuje třída TimetableActivity pomocí třídy MyFiltr a implementací, které jsou znázorněny na schématu č. 7.


Na následujícím obrázku je vykreslený rozvrh hodin. Snímek byl pořízen ze zařízení Nexus 7.


Súbor:Vykreslený rozvrh hodin, Nexus 7

Obrázek č. 14: Vykreslený rozvrh hodin, Nexus 7

Zdroj: vlastní


Na předcházejícím obrázku je zobrazena aplikace EPI rozvrh s vykresleným rozvrhem hodin a ovládacími prvky.


Balíček popups

Za běhu aplikace nastávají situace, kdy je potřeba informovat uživatele, nebo od něj vyžádat vstup. To se provádí pomocí dialogů, což jsou vyskakovací okna. Veškeré dialogy v rámci aplikace rozvrhu hodin jsou umístěny v tomto balíčku.

Súbor:Diagram balíčku popups

Schéma č. 11: Diagram balíčku popups

Zdroj: vlastní


Balíček popups se skládá ze dvou tříd MyFiltr a Detail, výčtového typu enum s názvem Filtr a rozhraní PopupCompleteListener. Třída MyFiltr pracuje s instancí rozhraní PopupCompleteListener a s instancí výčtového typu s názvem Filtr. Třída Detail je potomkem systémové třídy Dialog a pracuje s instancemi tříd CellData a TimetableTyp. Všechny popisované vazby jsou znázorněny na schématu č. 11.


Detail informační buňky z rozvrhu hodin

Informační buňka z rozvrhu hodin obsahuje spoustu informací, které nejsou zobrazeny v rozvrhu hodin. Pro jejich zobrazení je tedy použit dialog vyvolaný kliknutím na informační buňku, jenž je graficky upravený tak, aby v něm byly požadované informace srozumitelně a jednoduše zobrazeny, což je obrovská výhoda oproti stávajícímu rozvrhu hodin, který je dostupný na webových stránkách informačního systému školy.


Zobrazení dialogu zajišťuje třída Detail, která je potomkem třídy android.app.Dialog, což zajišťuje vyvolání dialogu po kliknutí na grafický prvek View, jež je předán jako parametr při vytváření instance třídy Detial. Při vytváření instance se také předávají data pro zobrazení ve formě objektu CellData a hodnota výčtového typu TimetableTyp.


Objekt CellData obsahuje veškeré informace určené k zobrazení v rámci dané buňky. Způsob zobrazení dat pro studenty, učitele a místnosti je rozdílný, i když jsou informace stejného charakteru, protože pro studenty je prioritní jiný typ informace než pro učitele nebo místnosti. K rozlišení způsobu zobrazení slouží výčtový typ s názvem TimetableTyp, jehož hodnota je předána právě při vytváření instance třídy.


Konstruktor třídy Detail:

public Detail(Context context, View view, CellData  cellData, TimetableType timTyp) {
super(context);
this.timTyp = timTyp;
this.cellData = cellData;
this.addListener(view);
}

V konstruktoru se převzaté objekty timTyp a cellData uloží do ekvivalentních proměnných patřících třídě Detail.

Metoda addListener(View):
private void addListener(View view) {
view.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Detail.this.show();
}
});
}

Jak je vidět, metoda addListener(View) nastaví na převzatý objekt posluchače, který se spustí po kliknutí. Posluchač poté v případě kliknutí na objekt View zobrazí dialog a zavolá metodu onCreate(), jež byla převzata od rodičovského prvku. V metodě onCreate() se pak zobrazí data a způsob zobrazení ovlivňuje hodnota globální proměnné timTyp.


Zobrazení rozvrhu hodin pomocí filtru

Každý uživatel aplikace si může zobrazit nejenom svůj rozvrh hodin, ale může si také zobrazit rozvrh hodin pro jednotlivé studenty, učitele a místnosti. Tuto vlastnost aplikace zajišťuje třída MyFiltr, která je potomkem systémové třídy Dialog, což zajišťuje, že se MyFiltr zobrazí jako dialog.


MyFiltr obsahuje tři grafická políčka a z toho dvě jsou výběrová tlačítka. Třetí políčko slouží k ručnímu zadávání. První políčko udává, jedná-li se o rozvrh hodin pro učitele, místnost nebo pro studijní kruh. Druhé výběrové tlačítko obsahuje zkratky učitelů, místností nebo studijních kruhů. Třetí políčko slouží k ručnímu zadávání zkratky s automatickou nápovědou. Po zadání dvou písmen se zobrazí nabídka, která je ovlivněná výběrem prvního políčka. V této nabídce je seznam zkratek pro učitele, místnosti nebo studijní kruhy, jejichž první dvě písmena byla zadána.


První výběrové tlačítko tedy vždy obsahuje hodnoty učitel, místnost a studijní kruh. Výběrem tohoto políčka se ovlivní druhé výběrové políčko a třetí políčko pro ruční zadání s nápovědou. Posledním grafickým prvkem je tlačítko, jehož zmáčknutí zavře zobrazovaný dialog a zobrazí rozvrh hodin podle zadaných kriterií.


Vytvořením instance třídy se nastaví vzhled dialogu na předem vytvořený design, který je definovaný v XML souboru s názvem my_filtr.xml. Dále dojde k přednastavení výběru tak, že se vybere první studijní kruh v seznamu. Uživatel tuto volbu pak může kdykoliv změnit.


Balíček widgets

Aplikace rozvrhu hodin poskytuje miniaplikaci na plochu, což je minimalizovaná verze aplikace zpracovaná tak, aby ji bylo možné zobrazit na domovské obrazovce zařízení. [33]


Minimalizovaná aplikace se zobrazuje ve formě seznamu vyučovacích hodin za období jednoho dne. Každých 30 minut se seznam aktualizuje a v případě, že dojde k ukončení některé výuky, odstraní se také ze seznamu.

Súbor:Diagram balíčku widget

Schéma č. 12: Diagram balíčku widget

Zdroj: vlastní


Dle schématu č. 12 se tato třída skládá z balíčků ViewsFactory, WidgetProvider a WidgetService. WidgetProvider se stará o zobrazení miniaplikace a její správu. ViewsFactory pomocí WidgetService naplní miniaplikaci hodnotami. Vzhled miniaplikace se skládá z hlavičky, kde je název aktuálního dne a datum dne. Dále jej tvoří ListView, který slouží k zobrazení jednotlivých dat rozvrhu hodin.


Súbor:Vzhled widgetu

Obrázek č. 15: Vzhled widgetu

Zdroj: vlastní


Jak lze vidět na obrázku č. 15, widget se skládá z několika prvků LinearLayout určující rozmístění vizuálních prvků. Jedná se především o prvky TextView, které jsou umístěny ve vertikálně orientovaném prvku, což způsobuje, že jsou tyto prvky TextView umístěny pod sebou. Dále následuje nejdůležitější část miniaplikace a to je ListView. ListView je posuvný seznam obsahující prvky rozvrhu hodin. Miniaplikaci je možné zobrazit pouze na domovské obrazovce zařízení, jehož verze operačního systému je vyšší než API 11.