Compare commits

...

32 commits
v1.0 ... master

Author SHA1 Message Date
Norbi Peti 87c056b690
Create README.md 2018-06-22 11:52:37 +02:00
Norbi Peti 866903b790
Aaand again (AppVeyor btw) 2018-02-12 20:37:33 +01:00
Norbi Peti 6854be7281
És megint 2018-02-12 20:34:11 +01:00
Norbi Peti 538fb1b47c
And again 2018-02-12 20:20:40 +01:00
Norbi Peti df6d850131
És megint 2018-02-12 20:17:31 +01:00
Norbi Peti 2ff64cd7c4
Let's try this again 2018-02-12 20:15:12 +01:00
Norbi Peti d3a987d526
ValueTuple frissítése, üres sornál hely. 2018-02-12 19:55:06 +01:00
Norbi Peti 074ed19236 Hely. szöveg felülre, óra elmarad és egyéb jav. 2017-10-03 17:00:02 +02:00
Norbi Peti 403fde579d Kisebb előrehaladás 2017-09-29 21:24:08 +02:00
Norbi Peti f4fc6d9278 Csengetés format javítva, long press elkezdve 2017-09-28 23:09:54 +02:00
Norbi Peti 34ede81265 Internethibát nem ír ki majdnem semmiképpen
És a percet 01 perc helyett 1 percként írja ki
2017-09-26 22:07:38 +02:00
Norbi Peti e5915c8082 A/B hét javítva, 09.01-től számolja már, egyéb jav.
- Kódanalízis, biztonsági attribútumok
- Hibakezelés javítva (internethiba, stb.)
2017-09-24 21:45:05 +02:00
Norbi Peti e46a588a9f Óra eltolás, auto. fr.-t nem jelzi egy ideig, gyakori óranevek 2017-09-07 23:07:18 +02:00
Norbi Peti 55ab6467f4 Hibajavítások
- Perjel támogatása osztálynévben
- Ha olyan osztályt talál a helyettesítésekben, amit nem ismer, frissít
- Beállítja az utolsó frissítés idejét, ha sikeres volt
- Törli az extra sorokat, ha nincs most ott egy óra sem, de előtte volt
- Üres óranevek esetében kiírja az azonosítót (új óráknál)
2017-09-05 16:52:19 +02:00
Norbi Peti 3733f54fb9 Hibajavítások, az órarendet az API-ből veszi
- Az üres sor beszúró javítva
- A timer.Change javítva
- Az órarendet most már az API kezeli, kiválasztó metódusok hozzáadva
- Egyéb javítások
2017-03-28 22:17:57 +02:00
Norbi Peti f8aeade139 Mégtöbb rövidítés, frissítés event kezelve, üres sorok berakva 2017-03-26 01:15:28 +01:00
Norbi Peti 95c72a2382 Frissítve C# 7.0-ra, tömörítések..., egyéb módosítások
A ConnectFaliure esetén javasolja, hogy indítsa újra az alkalmazást
2017-03-25 23:17:30 +01:00
Norbi Peti 45557da7bf Áthelyezés folytatva 2017-03-24 23:26:16 +01:00
Norbi Peti 318747b5bf Mozgatás a PCL-be elkezdve 2017-03-23 09:54:40 +01:00
Norbi Peti 33a7036ae8 Android függőség megszüntetve a PCL-ben 2017-03-23 08:30:13 +01:00
Norbi Peti d70df804fd Javítások 2017-03-17 21:27:45 +01:00
Norbi Peti 22ae2f6612 Javítások. Már nem crashel. Valamiért.
Nem látom az összefüggést.
2017-03-15 00:20:04 +01:00
Norbi Peti 8d9c339f19 Hibajavítások, kisebb változtatások 2017-03-11 23:11:44 +01:00
Norbi Peti de330e854c Beállítások menü és sötét/világos téma hozzáadva!
Több óra próbálkozással
De működik
2017-03-11 22:25:37 +01:00
Norbi Peti 665b3327f7 Mentés fejlesztve, áthelyezett óra kijelölése, javítások
- Minden mentett adat egy fájlba helyezve (data.json)
- Az áthelyezett órákat is ki lehet már jelölni
- Javítások
2017-03-11 16:11:08 +01:00
Norbi Peti 5a1c504f8c Javítások, a "van-e még óra" ellenőrzés javítva 2017-03-08 19:49:03 +01:00
Norbi Peti 0f2af248e0 Javítás javítva 2017-03-05 17:07:44 +01:00
Norbi Peti 58906b93b2 Órarendfrissítési bug javítva 2017-03-05 16:32:13 +01:00
Norbi Peti ea8fb6d78f Javítások
- Most már csak akkor nyitja meg a fájlokat, ha elkezdi a mentést (adatvesztést elkerülendő)
- A helyettesítéseknél most már több osztály is támogatott egyszerre
- A tanárt beírja az eredeti órából áthelyezésnél
- Osztály egyenlőség a nullokra is működik
- Megnyitáskor kétszeres frissítés javítva
- Az utolsó frissítést akkor is beállítja, ha nem sikerült, így nem fog folyamatosan próbálkozni offline
- A következő óránál most már a helyettesített adatokat mutatja
- Óra közben a "Jelenlegi óra" feliratot mutatja, nem a "következő"-t
- Ha nincs több óra, a következő napra görget, nem a maira
2017-03-01 19:03:26 +01:00
Norbi Peti 789df17422 Javítások, fejlesztések
- Most már mindenképpen elmenti az órarendet és az osztályokat, így nem maradnak nyitva a fájlok
- A progress bar pozíciója javítva
- A részleteknél is pirossal jelzi a helyettesítéseket
- Jobb hibakezelés betöltéskor
- Nem jelzi a frissítést, ha gyorsan zajlik le - hasznos, ha a program offline próbál meg frissíteni
- Automatikusan frissíti a helyettesítéseket, ha már több, mint egy órája volt frissítve (a háttérben nem)
- A mai napot középpontba helyezi
- Egyéb
2017-02-28 20:37:15 +01:00
Norbi Peti 74966f3076 Helyettesítések megjelennek, javítások, stb.
- Egy óra kijelölése megszüntethető egy üres órahelyre kattintva
- Elmenti a helyettesítéseket
- Piros színnel jelzi azokat az órákat, ahol ideiglenes változás történt
- Rákattintva kiírja a változásokat is
- Most már nem írja ki a következő órát vasárnap
2017-02-26 02:11:18 +01:00
Norbi Peti 0c6e2c7e09 Helyettesítések elkezdve, javítások
- Le tudja tölteni és el tudja menteni a helyettesítéseket
- Csak az ehetieket (vagy hétvégén a jövőhetieket) veszi figyelembe
- Megállapítja, hogy A vagy B hét van-e
- Órarend duplikációs bug javítva (vissza gombbal való kilépéskor nem törli őket, de újra betöltötte megnyitáskor)
- Az aktuális naphoz görget minden előtérbe kerüléskor és frissítéskor
- Most már nem mutatja a "Nincs több óra ma" feliratot
- Az egész tartalom függőlegesen görgethető, nem külön-külön (elforgatott módban pl.)
2017-02-24 23:59:45 +01:00
32 changed files with 1053 additions and 397 deletions

View file

@ -1,33 +1,51 @@
using HtmlAgilityPack;
using Java.Lang;
using Orarend.Events;
using SimpleTimerPortable;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Security;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Orarend
{
public static class API
{ //TODO: Beállítások: Téma (sötét, világos) (Android; platformfüggő beállítások), Előre megadott egyedi nevek használata
[DataContract]
public class API
{ //TODO: Előre megadott egyedi nevek használata
internal static API példány = new API(); //TODO: FrissítésHa1ÓraEltelt() mentés
private API()
{
}
/// <summary>
/// A kulcs az óra azonosítója
/// </summary>
[DataMember(Order = 1)]
public Dictionary<string, ÓraTípus> típusok { get; private set; } = new Dictionary<string, ÓraTípus>();
[DataMember]
public Osztály[] osztályok { get; private set; } = new Osztály[0]; //Ez az initializáció csak akkor fut le, ha nem tölti be fájlból
[DataMember(Order = 2)]
public List<Órarend> órarendek { get; private set; } = new List<Órarend>();
[DataMember(Order = 3)]
public Settings beállítások { get; private set; } = new Settings();
/// <summary>
/// <para>Visszatér az osztályok listájával.</para>
/// <para>Lehet null, ha még nem volt sikeres <see cref="Frissítés"/>.</para>
/// </summary>
/// <returns></returns>
public static Osztály[] Osztályok { get; private set; }
public static List<Órarend> Órarendek { get; } = new List<Órarend>();
public static Settings Beállítások { get; private set; } = new Settings();
public static List<Helyettesítés> Helyettesítések { get; } = new List<Helyettesítés>();
public static Osztály[] Osztályok { get => példány.osztályok; private set => példány.osztályok = value; }
public static List<Órarend> Órarendek { get { return példány.órarendek; } }
public static Settings Beállítások { get => példány.beállítások; private set => példány.beállítások = value; }
/// <summary>
/// Frissíti az osztálylistát és az eredeti órarendet, első megnyitásnál, és egy órarend hozzáadásánál/szerkesztésénél, majd hetente elegendő meghívni
/// <param name="órarendstream">A file stream, ahova mentse az adatokat, hogy ne kelljen külön meghívni</param>
/// <param name="osztálystream">A file stream, ahova mentse az adatokat, hogy ne kelljen külön meghívni</param>
/// <param name="stream">A file stream, ahova mentse az adatokat, hogy ne kelljen külön meghívni - Azért funkció, hogy elkerüljök az adatvesztést, mivel így csak a mentéskor nyitja meg</param>
/// </summary>
public static async Task Frissítés(Stream órarendstream, Stream osztálystream, Órarend ór = null)
public static async Task Frissítés(Func<Stream> stream, Órarend ór = null)
{
Func<string, Task<HtmlDocument>> load = async (url) =>
{
@ -39,7 +57,7 @@ namespace Orarend
using (var sr = new StreamReader(resp.GetResponseStream()))
{
const string trtd = @"(?:\s\w+=(?:\""|\')?(?:\w|[áéóüöőúű.:;])+(?:\""|\')?)*>(?!.+?\<table(?:\s\w+?=\""?\w+\""?)*\>.+?)(.+?)(?=<\1(?:\s\w+=(?:\""|\')?(?:\w|[áéóüöőúű.:;])+(?:\""|\')?)*>)";
string html = Regex.Replace(Regex.Replace(Regex.Replace(sr.ReadToEnd(), "<th([^>]*)>((?:\\w|[áéóüöőúű.])+)(?=<)(?!\\/)", "<th$1>$2</th>"), "<(tr)" + trtd, "<$1>$2</$1>"), "<(td)" + trtd, "<$1>$2</$1>");
string html = Regex.Replace(Regex.Replace(Regex.Replace(sr.ReadToEnd(), "<th([^>]*)>((?:\\w|[áéóüöőúű./])+)(?=<)(?!\\/)", "<th$1>$2</th>"), "<(tr)" + trtd, "<$1>$2</$1>"), "<(td)" + trtd, "<$1>$2</$1>");
doc.LoadHtml(html);
}
});
@ -52,86 +70,164 @@ namespace Orarend
}
Func<Órarend, Task> órarenda = async órarend =>
{
var doc = await load("http://deri.enaplo.net/ajax/orarend/orarendoszt.php?p=" + Uri.EscapeDataString(órarend.Osztály.Azonosító));
var doc = await load("https://deri.enaplo.net/ajax/orarend/orarendoszt.php?p=" + órarend.Osztály.Azonosító);
await Task.Run(() =>
{
Osztályok = doc.GetElementbyId("uok").ChildNodes.Where(node => node.HasAttributes).Select(node => new Osztály { Azonosító = node.GetAttributeValue("value", ""), Név = node.NextSibling.InnerText }).ToArray();
bool ahét = true;
foreach (var node in doc.GetElementbyId("oda").FirstChild.FirstChild.ChildNodes[1].ChildNodes)
lock (Órarendek)
{
switch (node.FirstChild.InnerText)
Osztályok = doc.GetElementbyId("uok").ChildNodes.Where(node => node.HasAttributes).Select(node => new Osztály { Azonosító = node.GetAttributeValue("value", ""), Név = node.NextSibling.InnerText }).ToArray();
bool ahét = true;
int maxx = 0;
foreach (var node in doc.GetElementbyId("oda").FirstChild.FirstChild.ChildNodes[1].ChildNodes)
{
case "A":
ahét = true;
break;
case "B":
ahét = false;
break;
default:
{
int x = int.Parse(node.FirstChild.InnerText) - 1;
órarend.Órakezdetek[x] = TimeSpan.Parse(node.FirstChild.Attributes["title"].Value.Split('-')[0].Trim());
for (int i = 0; i < 5; i++) //Napok
{
var óranode = node.ChildNodes[i + 1].FirstChild;
var óra = (ahét ? órarend.ÓrákAHét : órarend.ÓrákBHét)[i][x];
if (óranode.ChildNodes.Count == 0)
continue;
for (int j = 0; j < óranode.ChildNodes.Count; j += 6)
{
var csoport = óranode.ChildNodes[j].InnerText.TrimEnd(':');
if (csoport != "Egész osztály" && !órarend.Csoportok.Contains(csoport))
continue;
if (óra == null)
(ahét ? órarend.ÓrákAHét : órarend.ÓrákBHét)[i][x] = óra = new Óra();
óra.Csoportok = new string[] { csoport }; //Az állandó órarendben osztályonként csak egy csoport van egy órán
óra.Azonosító = óranode.ChildNodes[j + 2].InnerText;
óra.TeljesNév = óranode.ChildNodes[j + 2].Attributes["title"].Value;
óra.Terem = óranode.ChildNodes[j + 3].InnerText.Trim(' ', '(', ')');
óra.Tanár = new Tanár
{
Azonosító = óranode.ChildNodes[j + 4].InnerText,
Név = óranode.ChildNodes[j + 4].Attributes["title"].Value
};
break;
}
}
switch (node.FirstChild.InnerText)
{
case "A":
ahét = true;
break;
}
case "B":
ahét = false;
break;
default:
{
int x = int.Parse(node.FirstChild.InnerText) - 1, y = x - Beállítások.ÓraOffset;
maxx = x > maxx ? x : maxx;
if (y >= 0 && y < órarend.Órakezdetek.Length)
órarend.Órakezdetek[y] = TimeSpan.Parse(node.FirstChild.Attributes["title"].Value.Split('-')[0].Trim());
var órák = ahét ? órarend.ÓrákAHét : órarend.ÓrákBHét;
for (int i = 0; i < 5; i++) //Napok
{
var óranode = node.ChildNodes[i + 1].FirstChild;
var óra = órák[i][x];
if (óranode.ChildNodes.Count == 0)
{
órák[i][x] = null;
continue;
}
for (int j = 0; j < óranode.ChildNodes.Count; j += 6)
{
var csoport = óranode.ChildNodes[j].InnerText.TrimEnd(':');
if (csoport != "Egész osztály" && !órarend.Csoportok.Contains(csoport))
{
órák[i][x] = null;
continue;
}
if (óra == null)
órák[i][x] = óra = new Óra();
óra.Csoportok = new string[] { csoport }; //Az állandó órarendben osztályonként csak egy csoport van egy órán
óra.Azonosító = óranode.ChildNodes[j + 2].InnerText;
óra.TeljesNév = óranode.ChildNodes[j + 2].Attributes["title"].Value;
óra.Terem = óranode.ChildNodes[j + 3].InnerText.Trim(' ', '(', ')');
óra.Tanár = new Tanár
{
Azonosító = óranode.ChildNodes[j + 4].InnerText,
Név = óranode.ChildNodes[j + 4].Attributes["title"].Value
};
break;
}
}
break;
}
}
}
for (int i = maxx + 1; i < 16; i++) //Órák
for (int j = 0; j < 5; j++) //Napok
órarend.Órák[j][i] = null; //Kitörli a küldött órarendben nem szereplő órákat
}
Thread.Sleep(10);
});
await Task.Delay(10);
};
if (ór == null)
foreach (var órarend in Órarendek)
await órarenda(órarend);
else
await órarenda(ór);
ÓrarendMentés(órarendstream);
OsztályMentés(osztálystream);
Mentés(stream());
}
/// <summary>
/// Frissíti a helyettesítéseket, naponta, indításkor vagy gombnyommásra frissítse (minden nap az első előtérbe kerüléskor)
/// <param name="s">A file stream, ahova mentse az adatokat, hogy ne kelljen külön meghívni</param>
/// </summary>
public static async Task HelyettesítésFrissítés(Stream s)
/// <param name="stream">A file stream, ahova mentse az adatokat, hogy ne kelljen külön meghívni - Azért funkció, hogy elkerüljök az adatvesztést, mivel így csak a mentéskor nyitja meg</param>
public static async Task<bool> HelyettesítésFrissítés(Func<Stream> stream)
{
if (Órarendek.Count == 0 || Osztályok.Length == 0)
return false;
HtmlDocument doc = new HtmlDocument();
var req = WebRequest.CreateHttp("http://deri.enaplo.net/ajax/print/htlista.php");
var resp = await req.GetResponseAsync();
await Task.Run(() =>
{
using (var sr = new StreamReader(resp.GetResponseStream()))
doc.LoadHtml(sr.ReadToEnd());
}); //TODO
lock (Órarendek)
{
using (var sr = new StreamReader(resp.GetResponseStream()))
doc.LoadHtml(sr.ReadToEnd());
foreach (var órarend in Órarendek)
órarend.Helyettesítések.Clear();
foreach (var node in doc.DocumentNode.ChildNodes[2].ChildNodes[1].ChildNodes)
{
DateTime dátum = DateTime.Parse(node.ChildNodes[0].InnerText.Substring(0, node.ChildNodes[0].InnerText.Length - 4));
int hét = CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(dátum, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);
if (hét != Hét)
continue;
byte óraszám = byte.Parse(node.ChildNodes[1].InnerText);
var osztályok = node.ChildNodes[2].InnerText.Split(new string[] { ", " }, StringSplitOptions.None);
foreach (string osztálynév in osztályok)
{
Osztály osztály = Osztályok.SingleOrDefault(o => o.Azonosító.Contains(osztálynév));
if (osztály == null)
{
var x = new InvalidOperationException($"A helyettesítésekben szereplő osztály \"{osztálynév}\" nem található.");
x.Data.Add("OERROR", "CLS_NOT_FOUND");
throw x;
}
var csoportok = node.ChildNodes[3].InnerText;
int névindex = csoportok.IndexOf(osztálynév);
int végeindex = csoportok.IndexOf(")", névindex >= 0 ? névindex : 0);
string csoport = osztályok.Length == 1 ? csoportok : csoportok.Substring(névindex + osztálynév.Length + 1, végeindex - névindex - osztálynév.Length - 1);
string óraaz = node.ChildNodes[4].InnerText;
string terem = node.ChildNodes[5].InnerText.Split(new string[] { " -> " }, StringSplitOptions.None).Last(); //Mindig az új termet tárolja el, ha változott
string tanár = node.ChildNodes[7].InnerText;
string[] megj = node.ChildNodes[8].InnerText.Split(' ');
string óranév = node.ChildNodes[9].InnerText;
DayOfWeek újnap = dátum.DayOfWeek;
byte újsorszám = óraszám;
if (megj.Length > 2)
{
újnap = DateTime.Parse(megj[1]).DayOfWeek;
újsorszám = byte.Parse(megj[3].Trim('.'));
}
foreach (var órarend in (csoport == "Egész osztály" ? Órarendek : Órarendek.Where(ór => ór.Csoportok.Contains(csoport))).Where(ór => ór.Osztály == osztály))
{
if (tanár == "")
tanár = órarend.Órák[(int)dátum.DayOfWeek - 1][óraszám - 1]?.Tanár.Név ?? "";
var helyettesítés = new Helyettesítés { EredetiNap = dátum.DayOfWeek, EredetiSorszám = óraszám, ÚjÓra = tanár == "elmarad" ? null : new Óra { Azonosító = óraaz, Csoportok = new string[] { csoport }, Terem = terem, Tanár = new Tanár { Név = tanár }, TeljesNév = óranév }, ÚjNap = újnap, ÚjSorszám = újsorszám };
órarend.Helyettesítések.Add(helyettesítés);
}
}
}
}
Mentés(stream());
utolsófrissítésplusz1óra = DateTime.Now + new TimeSpan(1, 0, 0); //Mindenképpen állítsa be, hogy ne írja folyamatosan a hibát
});
return true;
}
private static T betöltés<T>(Stream s)
[OnDeserializing]
private void betöltés(StreamingContext context) => példány = this; //Az órák azonosítójának beállításakor szükséges már
/// <summary>
/// Betölti az adatokat, ha még nincsenek betöltve
/// </summary>
/// <param name="s">A stream, ahonnan betöltse az adatokat</param>
/// <param name="hibánál">Megadja, mi történjen egy hiba esetén</param>
/// <returns>Elvégezte-e a betöltést</returns>
public static bool Betöltés(Stream s, Action<Exception> hibánál)
{
using (s)
{
if (!!!betöltés())
return false;
using (var ms = new MemoryStream())
{
s.CopyTo(ms);
@ -140,69 +236,158 @@ namespace Orarend
try
{
ms.Seek(0, SeekOrigin.Begin);
var serializer = new DataContractJsonSerializer(typeof(T));
return (T)serializer.ReadObject(ms);
var serializer = new DataContractJsonSerializer(typeof(API));
serializer.ReadObject(ms); //A példányt beállítja, mikor elkezdi, nem várja meg, hogy végezzen (betöltés())
return true;
}
catch
catch (Exception e)
{
return default(T);
hibánál(e);
return Betöltés();
}
}
return default(T);
else return false;
}
}
}
} //TODO: Tényleges órarendből állapítsa meg azt is, hogyha egyáltalán nincs ott egy óra, és máshol sincs, és ezt írja ki
public static void ÓrarendBetöltés(Stream s)
/// <summary>
/// Betölti az alapértelemzett értékeket
/// <returns>Elvégezte-e a betöltést</returns>
/// </summary>
public static bool Betöltés()
{
Órarendek.AddRange(betöltés<Órarend[]>(s) ?? new Órarend[0]);
if (!betöltés())
return false;
példány = new API();
return true;
}
public static void OsztályBetöltés(Stream s)
private static Timer timer;
private static bool betöltés()
{
Osztályok = betöltés<Osztály[]>(s) ?? new Osztály[0];
if (!!(Órarendek.Count > 0 || Osztályok?.Length > 0 || timer != null))
return false;
timer = new Timer(CsengőTimer, null, new TimeSpan(0, 0, 0, 0, 100), new TimeSpan(0, 0, 5));
return true;
}
public static void BeállításBetöltés(Stream s)
{
Beállítások = betöltés<Settings>(s);
}
public static void HelyettesítésBetöltés(Stream s)
{ //TODO: Tényleges órarendből állapítsa meg azt is, hogyha egyáltalán nincs ott egy óra, és máshol sincs, és ezt írja ki
Helyettesítések.AddRange(betöltés<Helyettesítés[]>(s) ?? new Helyettesítés[0]);
}
private static void mentés<T>(Stream s, T obj)
public static void Mentés(Stream s)
{
using (s)
if (példány != null)
new DataContractJsonSerializer(példány.GetType()).WriteObject(s, példány);
}
/// <summary>
/// Visszatér a megjelenítendő héttel. Ez megegyezik a tényleges héttel, kivéve hétvégén, amikor a következő
/// </summary>
public static int Hét
{
get
{
if (obj != null)
{
var serializer = new DataContractJsonSerializer(typeof(T));
serializer.WriteObject(s, obj);
}
int jelenlegihét = napbólhét(DateTime.Today);
if (DateTime.Today.DayOfWeek > DayOfWeek.Friday || DateTime.Today.DayOfWeek == DayOfWeek.Sunday)
jelenlegihét++;
return jelenlegihét;
}
}
public static void ÓrarendMentés(Stream s)
private static int napbólhét(DateTime nap) => CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(nap, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);
public static bool AHét { get => Hét % 2 == napbólhét(new DateTime(DateTime.Today.Year - (DateTime.Today.Month < 8 ? 1 : 0), 9, 1)) % 2; }
public static bool Fókusz
{
mentés(s, Órarendek.ToArray());
set
{
if (value)
{
timer = timer.Change(new TimeSpan(0, 0, 0), new TimeSpan(0, 0, 5));
frissítésHa1ÓraEltelt();
}
else
timer.Cancel();
}
}
private static void OsztályMentés(Stream s)
private static DateTime utolsófrissítésplusz1óra = DateTime.MinValue;
public static event EventHandler<FrissítésEventArgs> Frissítéskor;
public class FrissítésEventArgs : EventArgs { public bool Siker { get; set; } = false; }
private static void frissítésHa1ÓraEltelt()
{
mentés(s, Osztályok);
if (utolsófrissítésplusz1óra > DateTime.Now)
return;
var args = new FrissítésEventArgs();
Frissítéskor?.Invoke(példány, args);
if (args.Siker)
utolsófrissítésplusz1óra = DateTime.Now + new TimeSpan(1, 0, 0);
}
public static void BeállításMentés(Stream s)
public static DayOfWeek MaiNap
{
mentés(s, Beállítások);
get
{
var x = DateTime.Today.DayOfWeek;
if (nincstöbbóra) x++;
return x > DayOfWeek.Saturday || x == DayOfWeek.Sunday ? DayOfWeek.Monday : x;
}
}
private static void HelyettesítésMentés(Stream s)
public static (Helyettesítés innen, Helyettesítés ide) HelyettesítésInnenIde(Órarend órarend, int i, int j) =>
(órarend.Helyettesítések.FirstOrDefault(h => (int)h.EredetiNap == i + 1 && h.EredetiSorszám == j + 1),
órarend.Helyettesítések.FirstOrDefault(h => (int)h.ÚjNap == i + 1 && h.ÚjSorszám == j + 1 && h.ÚjÓra != null));
//Ha az eredeti óra elmarad, és ide lesz helyezve egy másik, az áthelyezést mutassa
public static Órarend Órarend { get; private set; }
public static void ÓrarendKiválasztás(int position) { Órarend = Órarendek[position]; CsengőTimer(null); }
public static void ÓrarendKiválasztásTörlése() { Órarend = null; CsengőTimer(null); }
private static bool nincstöbbóra = false;
public static event EventHandler<TimerEventArgs> CsengőTimerEvent;
private static void CsengőTimer(object state) => CsengőTimerEvent?.Invoke(példány, CsengőTimer());
private static TimerEventArgs CsengőTimer()
{
mentés(s, Helyettesítések.ToArray());
if (Órarend == null)
return new TimerEventArgs(null, "Nincs órarend kiválasztva");
var most = DateTime.Now - DateTime.Today;
//var most = new TimeSpan(12, 46, 0);
bool talált = false;
if (Órarend.Órakezdetek[Beállítások.ÓraOffset] == TimeSpan.Zero) //Még nincsenek beállítva a kezdetek
return new TimerEventArgs(null, "Betöltés");
string kezdveg = null, kovora = null;
for (int i = 0; i < Órarend.Órakezdetek.Length - 1; i++)
{
var vége = Órarend.Órakezdetek[i].Add(new TimeSpan(0, 45, 0));
bool becsengetés;
int x = (int)DateTime.Today.DayOfWeek - 1;
Óra óra;
var (innen, ide) = HelyettesítésInnenIde(Órarend, x, i);
Func<TimeSpan, string> óraperc = ts => ts.Hours > 0 ? ts.ToString("h\\ómm\\p") : ts.ToString("%m") + " perc";
if (x != -1 && x < 6 && (óra = ide != null ? ide.ÚjÓra : innen != null ? innen.EredetiNap != innen.ÚjNap || innen.EredetiSorszám != innen.ÚjSorszám ? null : innen.ÚjÓra : Órarend.Órák[x][i]) != null)
{ //-1: Vasárnap
if (most > Órarend.Órakezdetek[i])
{
if (most < vége)
{
kezdveg = "Kicsengetés: " + óraperc(vége - most);
talált = true;
becsengetés = false;
}
else
continue;
}
else
{
kezdveg = "Becsengetés: " + óraperc(Órarend.Órakezdetek[i] - most);
talált = true;
becsengetés = true;
}
kovora = (becsengetés ? "Következő" : "Jelenlegi") + " óra: " + óra.EgyediNév + "\n" + óra.Terem + "\n" + óra.Tanár.Név + "\n" + óra.Csoportok.Aggregate((a, b) => a + ", " + b);
break;
}
}
nincstöbbóra = !talált;
return new TimerEventArgs(kovora, kezdveg);
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Orarend.Events
{
public class TimerEventArgs : EventArgs
{
/// <summary>
/// Lehet null
/// </summary>
public string KövetkezőÓra { get; }
/// <summary>
/// Lehet null
/// </summary>
public string HátralévőIdő { get; }
public TimerEventArgs(string kövóra, string hátralévőidő)
{
KövetkezőÓra = kövóra;
HátralévőIdő = hátralévőidő;
}
}
}

View file

@ -11,13 +11,11 @@ namespace Orarend
public class Helyettesítés
{
[DataMember]
public byte EredetiNap { get; set; }
public DayOfWeek EredetiNap { get; set; }
[DataMember]
public byte EredetiSorszám { get; set; }
[DataMember]
public Óra EredetiÓra { get; set; }
[DataMember]
public byte ÚjNap { get; set; }
public DayOfWeek ÚjNap { get; set; }
[DataMember]
public byte ÚjSorszám { get; set; }
[DataMember]

View file

@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{93C1582B-AD0F-44EC-BB69-02EE1ADFC0DD}</ProjectGuid>
@ -13,8 +13,8 @@
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile111</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkProfile>Profile44</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -33,24 +33,28 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<ItemGroup>
<Compile Include="API.cs" />
<Compile Include="Events\TimerEventArgs.cs" />
<Compile Include="Helyettesítés.cs" />
<Compile Include="Osztály.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Tanár.cs" />
<Compile Include="Timer.cs" />
<Compile Include="Óra.cs" />
<Compile Include="Órarend.cs" />
<Compile Include="ÓraTípus.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="HtmlAgilityPack, Version=1.4.9.4, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\HtmlAgilityPack.1.4.9.4\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid+MonoTouch\HtmlAgilityPack.dll</HintPath>
<Private>True</Private>
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\portable-net45+netcore45+wp8+MonoAndroid+MonoTouch\HtmlAgilityPack.dll</HintPath>
</Reference>
<Reference Include="Mono.Android">
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v6.0\Mono.Android.dll</HintPath>
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>..\packages\System.ValueTuple.4.4.0\lib\portable-net40+sl4+win8+wp8\System.ValueTuple.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@ -64,4 +68,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View file

@ -18,14 +18,12 @@ namespace Orarend
{
}
public override string ToString()
{
return Név;
}
public override string ToString() => Név;
public bool Equals(Osztály other)
{
return Azonosító == other.Azonosító;
}
public bool Equals(Osztály other) => Azonosító == other?.Azonosító;
public static bool operator==(Osztály a, Osztály b) => a?.Equals(b) ?? (object)b == null;
public static bool operator!=(Osztály a, Osztály b) => !(a == b);
public override bool Equals(object obj) => obj is Osztály ? Equals(obj as Osztály) : base.Equals(obj);
public override int GetHashCode() => Azonosító.GetHashCode();
}
}

View file

@ -2,6 +2,7 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
@ -15,6 +16,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: SecurityTransparent]
// Version information for an assembly consists of the following four values:
//

View file

@ -7,11 +7,9 @@ using System.Threading.Tasks;
namespace Orarend
{
[DataContract]
[DataContract] //
public class Settings
{
[DataMember]
public bool DarkTheme { get; set; }
public void UseCommonNames()
{
set("mateme", "Matek");
@ -20,6 +18,7 @@ namespace Orarend
set(";prggy", "Programozás gyakorlat");
set("testns", "Tesi");
set("tapism", "Töri");
set("torten", "Töri");
set("matema", "Matek");
set("bioege", "Biosz");
set("foldra", "Föci");
@ -31,5 +30,8 @@ namespace Orarend
if (ÓraTípus.Típusok.ContainsKey(id))
ÓraTípus.Típusok[id].EgyediNév = name;
}
[DataMember]
public sbyte ÓraOffset { get; set; } = 0;
}
}

48
Orarend/Timer.cs Normal file
View file

@ -0,0 +1,48 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace SimpleTimerPortable
{
internal delegate void TimerCallback(object state);
internal sealed class Timer : CancellationTokenSource, IDisposable
{
public Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
{
this.callback = callback;
this.state = state;
start(dueTime, period);
}
private TimerCallback callback;
private object state;
private void start(TimeSpan dueTime, TimeSpan period)
{
Task.Delay(dueTime, Token).ContinueWith(async (t, s) =>
{
var tuple = (Tuple<TimerCallback, object>)s;
while (true)
{
if (IsCancellationRequested)
break;
await Task.Run(() => tuple.Item1(tuple.Item2));
await Task.Delay(period);
}
}, Tuple.Create(callback, state), CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default);
}
public new void Dispose() { base.Cancel(); }
public Timer Change(TimeSpan dueTime, TimeSpan period)
{
var timer = new Timer(callback, state, dueTime, period);
this.Dispose();
return timer;
}
}
}

View file

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="HtmlAgilityPack" version="1.4.9.4" targetFramework="portable45-net45+win8+wpa81" />
</packages>
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="portable45-net45+wp8" />
<package id="System.Collections" version="4.3.0" targetFramework="portable46-net451+win81" />
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="portable46-net451+win81" />
<package id="System.Runtime" version="4.3.0" targetFramework="portable46-net451+win81" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="portable46-net451+win81" />
</packages>

View file

@ -10,7 +10,6 @@ namespace Orarend
[DataContract]
public class Óra
{
[DataMember]
private ÓraTípus Típus { get; set; }
[DataMember]
public Tanár Tanár { get; set; }
@ -21,7 +20,11 @@ namespace Orarend
/// </summary>
[DataMember]
public string[] Csoportok { get; set; }
[DataMember]
public bool ManuálisanHozzáadott { get; set; }
[DataMember]
public string Azonosító
{
get

View file

@ -7,15 +7,29 @@ namespace Orarend
public class ÓraTípus
{
[DataMember]
public string TeljesNév { get; set; }
private string teljesnév;
public string TeljesNév
{
get
{
return teljesnév;
}
set
{
if ((value?.Trim()?.Length ?? 0) == 0)
teljesnév = "(" + Azonosító + ")";
else
teljesnév = value;
}
}
[DataMember]
public string Azonosító { get; set; }
[DataMember]
public string EgyediNév { get; set; }
/// <summary>
/// A kulcs az óra azonosítója
/// </summary>
public static Dictionary<string, ÓraTípus> Típusok { get; } = new Dictionary<string, ÓraTípus>();
public static Dictionary<string, ÓraTípus> Típusok { get { return API.példány.típusok; } }
}
}

View file

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Security;
using System.Text;
using System.Threading.Tasks;
@ -10,18 +11,21 @@ namespace Orarend
[DataContract]
public class Órarend
{
[DataMember]
internal Óra[][] ÓrákAHét { get; private set; } = new Óra[6][] { new Óra[16], new Óra[16], new Óra[16], new Óra[16], new Óra[16], new Óra[16] };
[DataMember]
internal Óra[][] ÓrákBHét { get; private set; } = new Óra[6][] { new Óra[16], new Óra[16], new Óra[16], new Óra[16], new Óra[16], new Óra[16] }; //Multidimensional arrays are not supported (serialization)
/// <summary>
/// <para>Egy 6x16 2D tömb, az első koordináta a nap indexe, a második az óráé. Az értékek lehetnek null-ok, ha nincs óra az adott időpontban</para>
/// <para>Egy <see cref="API.Frissítés"/> hívás állítja be az órákat</para>
/// </summary>
[DataMember]
public Óra[][] ÓrákAHét { get; private set; } = new Óra[6][] { new Óra[16], new Óra[16], new Óra[16], new Óra[16], new Óra[16], new Óra[16] };
/// <summary>
/// <para>Egy 6x16 2D tömb, az első koordináta a nap indexe, a második az óráé. Az értékek lehetnek null-ok, ha nincs óra az adott időpontban</para>
/// <para>Egy <see cref="API.Frissítés"/> hívás állítja be az órákat</para>
/// </summary>
[DataMember]
public Óra[][] ÓrákBHét { get; private set; } = new Óra[6][] { new Óra[16], new Óra[16], new Óra[16], new Óra[16], new Óra[16], new Óra[16] }; //Multidimensional arrays are not supported (serialization)
public Óra[][] Órák
{
get
{
return API.AHét ? ÓrákAHét : ÓrákBHét;
}
}
/// <summary>
/// <para>Egy <see cref="API.Frissítés"/> hívás állítja be</para>
/// </summary>
@ -36,6 +40,8 @@ namespace Orarend
public TimeSpan[] Órakezdetek { get; private set; } = new TimeSpan[16]; //A private set kell a serialization miatt
[DataMember]
public string[] Csoportok { get; set; }
[DataMember]
public List<Helyettesítés> Helyettesítések { get; private set; } = new List<Helyettesítés>();
/// <summary>
/// Létrehoz egy új órarendet

View file

@ -0,0 +1,28 @@
using Android.App;
using Android.OS;
using Android.Preferences;
using System.Security;
namespace OrarendAndroidApp
{
public class ActivityBase : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetTheme(this);
}
public static void SetTheme(Activity activity)
{
var settings = PreferenceManager.GetDefaultSharedPreferences(activity);
bool darktheme = settings.GetBoolean("pref_theme", false);
if (activity is ActivityBase ab)
ab.DarkTheme = darktheme;
activity.SetTheme(darktheme ? Android.Resource.Style.ThemeDeviceDefault : Android.Resource.Style.ThemeDeviceDefaultLight);
}
public bool DarkTheme;
}
}

View file

@ -11,11 +11,13 @@ using Android.Views;
using Android.Widget;
using Orarend;
using Android.Graphics;
using Android.Preferences;
using System.Security;
namespace OrarendAndroidApp
{
[Activity(Label = "AddActivity", Theme = "@android:style/Theme.Holo.Light")]
public class EditActivity : Activity
public class EditActivity : ActivityBase
{
private bool add;
private int index;
@ -44,6 +46,9 @@ namespace OrarendAndroidApp
osztálySpinner.SetSelection(ix);
FindViewById<EditText>(Resource.Id.csoportokEditText).Text = órarend.Csoportok.Aggregate((a, b) => a + " " + b);
}
else
FindViewById<EditText>(Resource.Id.névEditText).Text = "Órarend";
osztálySpinner.LayoutParameters = new TableRow.LayoutParams((osztálySpinner.Parent as View)?.Width - (osztálySpinner.Parent as ViewGroup)?.GetChildAt(0)?.Width ?? TableRow.LayoutParams.MatchParent, TableRow.LayoutParams.WrapContent); //TODO
FindViewById<Button>(Resource.Id.saveButton).Click += SaveButtonClick;
var deleteButton = FindViewById<Button>(Resource.Id.deleteButton);
if (add)
@ -66,7 +71,7 @@ namespace OrarendAndroidApp
intent.PutExtra("deleted", true);
((AlertDialog)s).Dismiss();
((AlertDialog)s).Dispose();
API.ÓrarendMentés(OpenFileOutput("orarend", FileCreationMode.Private));
API.Mentés(OpenFileOutput(MainActivity.DATA_FILENAME, FileCreationMode.Private));
SetResult(Result.Ok, intent);
Finish();
}).SetNegativeButton("Nem", (s, ea) =>
@ -90,7 +95,7 @@ namespace OrarendAndroidApp
}
else
API.Órarendek.Add(new Órarend(név, osztály, csoportok));
API.ÓrarendMentés(OpenFileOutput("orarend", FileCreationMode.Private));
API.Mentés(OpenFileOutput(MainActivity.DATA_FILENAME, FileCreationMode.Private));
SetResult(Result.Ok, Intent);
Finish();
}

View file

@ -8,52 +8,58 @@ using Android.OS;
using Orarend;
using System.Linq;
using Android.Graphics;
using Java.Lang;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using System.Net;
using Android.Preferences;
using Orarend.Events;
using System.Security;
namespace OrarendAndroidApp
{
[Activity(Label = "Órarend", MainLauncher = true, Theme = "@android:style/Theme.Holo.Light")]
public class MainActivity : Activity
[Activity(Label = "Órarend", MainLauncher = true, Theme = "@android:style/Theme.DeviceDefault")]
public class MainActivity : ActivityBase
{
private Handler handler;
private Órarend órarend;
private const int EDIT_ADD_ACT_REQUEST = 1;
private const int SETTINGS_ACT_REQUEST = 2;
public const string DATA_FILENAME = "data.json";
protected override void OnCreate(Bundle bundle)
{
AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironment_UnhandledExceptionRaiser;
base.OnCreate(bundle);
SetContentView(Resource.Layout.MainLayout);
ActionBar.SetDisplayShowTitleEnabled(false);
ActionBar.CustomView = FindViewById<Spinner>(Resource.Id.spinner);
handler = new Handler();
string[] list = FileList();
if (list.Contains("beallitasok"))
API.BeállításBetöltés(OpenFileInput("beallitasok"));
if (list.Contains("orarend"))
API.ÓrarendBetöltés(OpenFileInput("orarend"));
if (list.Contains("osztaly"))
API.OsztályBetöltés(OpenFileInput("osztaly"));
if (list.Contains("helyettesites"))
API.HelyettesítésBetöltés(OpenFileInput("helyettesites"));
var timer = new Timer(CsengőTimer, null, TimeSpan.Zero, new TimeSpan(0, 0, 1));
if (API.Órarendek.Count > 0)
if (list.Contains(DATA_FILENAME)
? API.Betöltés(OpenFileInput(DATA_FILENAME), e => Hiba("Hiba az adatok betöltése során!\n" + e)) : API.Betöltés())
{
órarend = API.Órarendek.First();
órarendfrissítés();
API.CsengőTimerEvent += CsengőTimer;
API.Frissítéskor += (_, args) => HelyettesítésFrissítés(false, args);
}
}
protected override void OnDestroy()
{
base.OnDestroy();
}
private void AndroidEnvironment_UnhandledExceptionRaiser(object sender, RaiseThrowableEventArgs e)
{
if (!e.Handled) Hiba("Kezeletlen hiba!\n" + e.Exception);
e.Handled = true;
}
private Spinner list;
private void órarendlistafrissítés()
{
handler.Post(() =>
{
var list = FindViewById<Spinner>(Resource.Id.spinner);
int selected = list.SelectedItemPosition;
int count = list.Count;
ArrayAdapter adapter;
@ -78,78 +84,111 @@ namespace OrarendAndroidApp
private void ÓrarendClick(object sender, AdapterView.ItemSelectedEventArgs e)
{
órarend = API.Órarendek[e.Position];
API.ÓrarendKiválasztás(e.Position);
órarendfrissítés();
}
private void addCell(string text, Color color, TableRow tr1, bool clickable = false, int[] tag = null)
[SecuritySafeCritical]
private void addCell(string text, Color color, TableRow tr1, (int, int)? tag = null)
{
TextView textview = new TextView(this);
textview.SetText(text, TextView.BufferType.Normal);
textview.SetTextColor(color);
textview.SetPadding(10, 10, 10, 10);
textview.SetBackgroundResource(Resource.Drawable.cell_shape_light);
textview.Tag = tag;
if (textview.Clickable = clickable)
textview.Click += ÓraClick;
textview.SetBackgroundResource(DarkTheme ? Resource.Drawable.cell_shape_dark : Resource.Drawable.cell_shape_light);
textview.Tag = tag.HasValue ? new JavaTuple<int, int>(tag.Value) : null;
textview.Clickable = true;
textview.Click += ÓraClick;
//textview.LongClick += ÓraLongClick;
RegisterForContextMenu(textview);
textview.ContextMenuCreated += ÓraContextMenuCreated;
tr1.AddView(textview);
}
private void HelyettesítésFrissítés()
[SecuritySafeCritical]
private class JavaTuple<T1, T2> : Java.Lang.Object
{
public (T1, T2) obj;
public JavaTuple((T1, T2) obj) => this.obj = obj;
public void Deconstruct(out T1 first, out T2 second) => (first, second) = obj;
}
private void HelyettesítésFrissítés(bool internethiba = true, API.FrissítésEventArgs args = null)
{
var bar = FindViewById<ProgressBar>(Resource.Id.progressBar1);
handler.Post(() => bar.Visibility = ViewStates.Visible);
API.HelyettesítésFrissítés(OpenFileOutput("helyettesites", FileCreationMode.Private)).ContinueWith(t =>
//var menu = FindViewById<ActionMenuView>(Resource.Id.actionMenuView1);
Action loadstart = () => bar.Visibility = ViewStates.Visible;
if (internethiba)
handler.Post(loadstart);
else
handler.PostDelayed(loadstart, 500);
API.HelyettesítésFrissítés(() => OpenFileOutput(DATA_FILENAME, FileCreationMode.Private)).ContinueWith(t =>
{
handler.RemoveCallbacks(loadstart);
handler.Post(() =>
{
bar.Visibility = ViewStates.Gone;
Toast.MakeText(this, "Helyettesítések frissítve", ToastLength.Short).Show();
});
});
}
private void ÓrarendFrissítés(Órarend ór = null)
{ //TODO: Meghívni minden tervezett alkalommal; hozzáadásnál csak a hozzáadott órarendet frissítse
var bar = FindViewById<ProgressBar>(Resource.Id.progressBar1);
handler.Post(() => bar.Visibility = ViewStates.Visible);
API.Frissítés(OpenFileOutput("orarend", FileCreationMode.Private), OpenFileOutput("osztaly", FileCreationMode.Private), ór).ContinueWith(t =>
{
handler.Post(() =>
{
if (TaskHiba(t) && (ór == null || ór == órarend))
if (TaskHibaNemVolt(t, internethiba) && t.Result)
{
órarendfrissítés();
bar.Visibility = ViewStates.Gone;
órarendlistafrissítés();
Toast.MakeText(this, "Órarend" + (ór == null ? "ek" : "") + " és osztálylista frissítve", ToastLength.Short).Show();
Toast.MakeText(this, "Helyettesítések frissítve", ToastLength.Short).Show();
if (args != null) args.Siker = true;
}
else if (!internethiba && args != null) args.Siker = true;
});
});
}
private void ÓrarendFrissítés(bool auto, Órarend ór = null)
{
var bar = FindViewById<ProgressBar>(Resource.Id.progressBar1);
Action loadstart = () => bar.Visibility = ViewStates.Visible;
if (auto)
handler.PostDelayed(loadstart, 500);
else
handler.Post(loadstart);
API.Frissítés(() => OpenFileOutput(DATA_FILENAME, FileCreationMode.Private), ór).ContinueWith(t =>
{
handler.RemoveCallbacks(loadstart);
handler.Post(() =>
{
bar.Visibility = ViewStates.Gone;
órarendlistafrissítés();
HelyettesítésFrissítés();
if (TaskHibaNemVolt(t))
{
if (ór == null || ór == API.Órarend)
órarendfrissítés();
Toast.MakeText(this, (API.Órarendek.Count > 0 ? "Órarend" + (ór == null ? "ek" : "") + " és o" : "O") + "sztálylista frissítve", ToastLength.Short).Show();
}
});
});
}
private string[] Napok = new string[6] { "Hétfő", "Kedd", "Szerda", "Csütörtök", "Péntek", "Szombat" };
[SecuritySafeCritical]
private void órarendfrissítés()
{
var table = FindViewById<TableLayout>(Resource.Id.tableLayout1);
if (table.ChildCount > 1)
table.RemoveViews(1, table.ChildCount - 1);
FindViewById<TextView>(Resource.Id.kivoraTV).Visibility = ViewStates.Gone;
if (órarend == null)
deselect();
if (table.ChildCount > 0)
table.RemoveViews(0, table.ChildCount);
if (API.Órarend == null)
return;
TableRow tr = new TableRow(this);
addCell("", Color.Black, tr);
addCell("Hétfő", Color.Black, tr);
addCell("Kedd", Color.Black, tr);
addCell("Szerda", Color.Black, tr);
addCell("Csütörtök", Color.Black, tr);
addCell("Péntek", Color.Black, tr);
addCell("Szombat", Color.Black, tr);
addCell(API.AHét ? "A" : "B", DarkTheme ? Color.White : Color.Black, tr);
for (int i = 0; i < Napok.Length; i++)
addCell(Napok[i], DarkTheme ? Color.White : Color.Black, tr);
table.AddView(tr, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent));
byte rowadds = 0;
for (int j = 0; j < 16; j++)
{
tr = new TableRow(this);
bool notnull = false;
for (int i = 0; i < 6; i++)
{ //Kihagyja az üres sorokat
if (órarend.ÓrákAHét[i][j] != null)
if (API.Órarend.Órák[i][j] != null && API.HelyettesítésInnenIde(API.Órarend, i, j).Item2 != null)
{
notnull = true;
break;
@ -157,44 +196,159 @@ namespace OrarendAndroidApp
}
if (notnull)
{
addCell((j + 1).ToString(), Color.Black, tr);
for (int x = 0; x < rowadds; x++)
{
var tr1 = new TableRow(this);
addCell((j + x).ToString(), DarkTheme ? Color.White : Color.Black, tr1);
for (int i = 0; i < 6; i++)
addCell("", Color.Black, tr1);
table.AddView(tr1, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent));
}
rowadds = 0;
addCell((j + 1).ToString(), DarkTheme ? Color.White : Color.Black, tr);
for (int i = 0; i < 6; i++)
addCell(órarend.ÓrákAHét[i][j] != null ? órarend.ÓrákAHét[i][j].EgyediNév : "", Color.Black, tr, true, new int[2] { i, j });
{
var (innen, ide) = API.HelyettesítésInnenIde(API.Órarend, i, j);
addCell(ide != null ? ide.ÚjÓra.EgyediNév : innen != null ? innen.EredetiNap != innen.ÚjNap || innen.EredetiSorszám != innen.ÚjSorszám ? "áthelyezve" : innen.ÚjÓra?.EgyediNév ?? "elmarad" : API.Órarend.Órák[i][j]?.EgyediNév ?? "", innen == null ? (DarkTheme ? Color.WhiteSmoke : Color.Black) : Color.Red, tr, (i, j));
}
table.AddView(tr, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent));
}
else rowadds++;
}
handler.Post(() => MaiNaphozGörgetés());
}
private (int i, int j, Óra óra, Helyettesítés innen, Helyettesítés ide)? TV2Óra(TextView tv)
{
var ij = (JavaTuple<int, int>)tv.Tag;
int i, j;
Helyettesítés innen, ide;
Óra óra;
if (ij != null)
{
(i, j) = ij;
(innen, ide) = API.HelyettesítésInnenIde(API.Órarend, i, j);
if ((óra = API.Órarend.Órák[i][j]) == null && ide?.ÚjÓra == null)
return null;
}
else
return null;
return (i, j, óra, innen, ide);
}
/// <summary>
/// A cellát nem frissíti, csak a szöveget tünteti el
/// </summary>
private void deselect()
{
FindViewById<TextView>(Resource.Id.kivoraTV).Visibility = ViewStates.Gone;
FindViewById<TextView>(Resource.Id.helyTV).Visibility = ViewStates.Gone;
selected = null;
}
private TextView selected;
/// <summary>
/// Kiválasztja az adott órát
/// </summary>
[SecuritySafeCritical]
private void ÓraClick(object sender, EventArgs e)
{
var tv = (TextView)sender;
var ij = (int[])tv.Tag;
Óra óra = órarend.ÓrákAHét[ij[0]][ij[1]];
if (óra == null)
return;
if (selected != null && selected != sender)
selected.SetBackgroundResource(Resource.Drawable.cell_shape_light);
tv.SetBackgroundResource(Resource.Drawable.cell_shape_selected_light);
selected.SetBackgroundResource(DarkTheme ? Resource.Drawable.cell_shape_dark : Resource.Drawable.cell_shape_light);
var x = TV2Óra(tv);
if (x == null)
{
deselect();
return;
}
var (i, j, óra, helyettesítésInnen, helyettesítésIde) = x?.ToTuple();
tv.SetBackgroundResource(DarkTheme ? Resource.Drawable.cell_shape_selected_dark : Resource.Drawable.cell_shape_selected_light);
selected = tv;
var kivora = FindViewById<TextView>(Resource.Id.kivoraTV);
kivora.Text = ((TextView)((TableRow)FindViewById<TableLayout>(Resource.Id.tableLayout1).GetChildAt(1)).GetChildAt(ij[0] + 1)).Text + " " + (ij[1] + 1) + ". óra\n"
+ óra.TeljesNév + "\n"
+ óra.Terem + "\n"
+ óra.Tanár.Név + "\n"
+ órarend.Órakezdetek[ij[1]].ToString("hh\\:mm") + "-" + órarend.Órakezdetek[ij[1]].Add(new TimeSpan(0, 45, 0)).ToString("hh\\:mm") + "\n"
+ óra.Csoportok.Aggregate((a, b) => a + ", " + b);
kivora.Visibility = ViewStates.Visible;
if (óra == null)
kivora.Visibility = ViewStates.Gone;
else
{
kivora.Text = Napok[i] + " " + (j + 1) + ". óra"
+ "\nNév: " + óra.TeljesNév
+ "\nTerem: " + óra.Terem
+ "\nTanár: " + óra.Tanár.Név
+ "\nIdőtartam: " + API.Órarend.Órakezdetek[j].ToString("hh\\:mm") + "-" + API.Órarend.Órakezdetek[j].Add(new TimeSpan(0, 45, 0)).ToString("hh\\:mm")
+ "\nCsoport: " + óra.Csoportok.Aggregate((a, b) => a + ", " + b);
kivora.Visibility = ViewStates.Visible;
}
var hely = FindViewById<TextView>(Resource.Id.helyTV);
hely.Text = (helyettesítésInnen == null ? ""
: helyettesítésInnen.EredetiNap != helyettesítésInnen.ÚjNap || helyettesítésInnen.EredetiSorszám != helyettesítésInnen.ÚjSorszám
? "Áthelyezve: innen --> " + Napok[(int)helyettesítésInnen.ÚjNap - 1] + " " + helyettesítésInnen.ÚjSorszám + ". óra"
: helyettesítésInnen.ÚjÓra != null && helyettesítésInnen.ÚjÓra != óra
? "Helyettesítés:"
+ (helyettesítésInnen.ÚjÓra.EgyediNév != óra.EgyediNév ? "\nÓra: " + helyettesítésInnen.ÚjÓra.EgyediNév : "")
+ (helyettesítésInnen.ÚjÓra.Terem != óra.Terem ? "\nTerem: " + helyettesítésInnen.ÚjÓra.Terem : "")
+ (helyettesítésInnen.ÚjÓra.Tanár.Név != óra.Tanár.Név ? "\nTanár: " + helyettesítésInnen.ÚjÓra.Tanár.Név : "")
+ (helyettesítésInnen.ÚjÓra.Csoportok[0] != óra.Csoportok[0] ? "\nCsoport: " + helyettesítésInnen.ÚjÓra.Csoportok.Aggregate((a, b) => a + ", " + b) : "")
: helyettesítésIde != null && (helyettesítésIde.EredetiNap != helyettesítésIde.ÚjNap || helyettesítésIde.EredetiSorszám != helyettesítésIde.ÚjSorszám)
? "" : "Az óra elmarad") //Ha át lett helyezve ide másik óra, akkor nem kell kiírni, hogy elmarad ez az óra
+ (helyettesítésIde == null ? ""
: helyettesítésIde.EredetiNap != helyettesítésIde.ÚjNap || helyettesítésIde.EredetiSorszám != helyettesítésIde.ÚjSorszám
? "Áthelyezve: " + Napok[(int)helyettesítésIde.EredetiNap - 1] + " " + helyettesítésIde.EredetiSorszám + ". óra --> ide"
+ (helyettesítésIde.ÚjÓra.EgyediNév != óra?.EgyediNév ? "\nÓra: " + helyettesítésIde.ÚjÓra.EgyediNév : "")
+ (helyettesítésIde.ÚjÓra.Terem != óra?.Terem ? "\nTerem: " + helyettesítésIde.ÚjÓra.Terem : "")
+ ((óra?.Tanár.Név != (helyettesítésIde.ÚjÓra.Tanár.Név == "" ? API.Órarend.Órák[(int)helyettesítésIde.EredetiNap - 1][helyettesítésIde.EredetiSorszám - 1].Tanár.Név : helyettesítésIde.ÚjÓra.Tanár.Név)) ? "\nTanár: " + (óra?.Tanár.Név == "" ? API.Órarend.Órák[(int)helyettesítésIde.EredetiNap - 1][helyettesítésIde.EredetiSorszám - 1].Tanár.Név : helyettesítésIde.ÚjÓra.Tanár.Név) : "")
+ (helyettesítésIde.ÚjÓra.Csoportok[0] != óra?.Csoportok[0] ? "\nCsoport: " + helyettesítésIde.ÚjÓra.Csoportok.Aggregate((a, b) => a + ", " + b) : "") //ˇˇ De ha változott, akkor nem
: "") //Ha a pozicíó nem változott, a fentebbi rész már kiírta az adatait
;
hely.Visibility = hely.Text.Length > 0 ? ViewStates.Visible : ViewStates.Gone;
}
private void ÓraContextMenuCreated(object sender, View.CreateContextMenuEventArgs e)
{
switch (sender)
{
case TextView tv:
var x = TV2Óra(tv);
Óra óra;
if (x != null)
(_, _, óra, _, _) = x?.ToTuple();
else
óra = null;
if (óra == null)
{ //TODO
ÓraContextItemData.Add(e.Menu.Add("Hozzáadás"), () => StartActivity(new Intent(this, typeof(SettingsActivity))));
}
break;
default:
Hiba("Ismeretlen küldő a menühöz!");
break;
}
}
private Dictionary<IMenuItem, Action> ÓraContextItemData = new Dictionary<IMenuItem, Action>();
private T ctor<T>() where T : new() => new T();
public override bool OnContextItemSelected(IMenuItem item)
{
bool ret = ÓraContextItemData.ContainsKey(item);
if (ret)
ÓraContextItemData[item]();
return ret;
}
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.main_menu_light, menu);
ActionBar.SetCustomView(list = new Spinner(this, SpinnerMode.Dropdown), new ActionBar.LayoutParams(ActionBar.LayoutParams.MatchParent, ActionBar.LayoutParams.MatchParent, GravityFlags.Left));
ActionBar.SetDisplayShowCustomEnabled(true);
if (DarkTheme)
{
menu.FindItem(Resource.Id.menu_add).SetIcon(Resource.Drawable.ic_add_white_24dp);
menu.FindItem(Resource.Id.menu_edit).SetIcon(Resource.Drawable.ic_create_white_24dp);
menu.FindItem(Resource.Id.menu_refresh).SetIcon(Resource.Drawable.ic_autorenew_white_24dp);
menu.FindItem(Resource.Id.menu_preferences).SetIcon(Resource.Drawable.ic_settings_white_24dp);
}
if (API.Osztályok == null || API.Osztályok.Length == 0)
ÓrarendFrissítés();
ÓrarendFrissítés(true);
else
órarendlistafrissítés();
return base.OnCreateOptionsMenu(menu);
@ -218,50 +372,60 @@ namespace OrarendAndroidApp
}
case Resource.Id.menu_edit:
{
if (órarend == null)
if (API.Órarend == null)
{
Toast.MakeText(this, "Nincs órarend kiválasztva", ToastLength.Short).Show();
break;
}
var intent = new Intent(this, typeof(EditActivity));
intent.PutExtra("add", false);
intent.PutExtra("index", API.Órarendek.IndexOf(órarend));
intent.PutExtra("index", API.Órarendek.IndexOf(API.Órarend));
StartActivityForResult(intent, EDIT_ADD_ACT_REQUEST);
break;
}
case Resource.Id.menu_preferences: //TODO
break;
case Resource.Id.menu_preferences:
{
var intent = new Intent(this, typeof(SettingsActivity));
StartActivityForResult(intent, SETTINGS_ACT_REQUEST);
break;
}
case Resource.Id.menu_fullrefresh:
{
ÓrarendFrissítés();
ÓrarendFrissítés(false);
break;
}
}
return base.OnOptionsItemSelected(item);
}
private void Hiba(string msg)
{
Hiba(this, msg);
}
private void Hiba(string msg) => Hiba(this, msg);
public static void Hiba(Context c, string msg)
{
public static void Hiba(Context c, string msg) =>
new AlertDialog.Builder(c).SetMessage(msg).SetNeutralButton("OK", (s, e) => { ((AlertDialog)s).Dismiss(); ((AlertDialog)s).Dispose(); }).SetTitle("Hiba").Show();
}
/// <summary>
/// Az összes hibát kiírja, ami a <see cref="Task"/> futása közben keletkezett
/// </summary>
/// <param name="t"></param>
/// <param name="internethiba">Ha igaz, kiírja a WebException-öket is</param>
/// <returns>Igaz, ha nem volt hiba</returns>
private bool TaskHiba(Task t)
private bool TaskHibaNemVolt(Task t, bool internethiba = true)
{
bool ret = true;
foreach (var ex in (IEnumerable<System.Exception>)t.Exception?.InnerExceptions ?? new System.Exception[0])
foreach (var ex in (IEnumerable<Exception>)t.Exception?.InnerExceptions ?? new Exception[0])
{
if (ex is WebException)
Hiba("Nem sikerült csatlakozni az E-naplóhoz.\n" + ex.Message);
if (ex is WebException wex)
{
if (internethiba && wex.Status == WebExceptionStatus.ConnectFailure)
Hiba("Nem sikerült csatlakozni az E-naplóhoz.\nHa van internet, próbáld újraindítani az alkalmazást.");
else if (internethiba)
Hiba("Nem sikerült csatlakozni az E-naplóhoz.\n" + wex.Message);
}
else if (ex is InvalidOperationException oex && oex.Data.Contains("OERROR") && (string)oex.Data["OERROR"] == "CLS_NOT_FOUND")
{
ÓrarendFrissítés(true);
Toast.MakeText(this, oex.Message, ToastLength.Short).Show();
}
else
Hiba(ex.ToString());
ret = false;
@ -269,82 +433,60 @@ namespace OrarendAndroidApp
return ret;
}
private void CsengőTimer(object state)
private void CsengőTimer(object sender, TimerEventArgs e)
{
handler.Post(() =>
{
var kezdveg = FindViewById<TextView>(Resource.Id.kezdvegTV);
if (órarend == null)
{
kezdveg.Text = "Nincs órarend kiválasztva";
return;
}
var most = DateTime.Now - DateTime.Today;
bool talált = false;
var kovora = FindViewById<TextView>(Resource.Id.kovoraTV);
if (órarend.Órakezdetek[0] == TimeSpan.Zero)
{ //Még nincsenek beállítva a kezdetek
kezdveg.Text = "Betöltés";
kovora.Visibility = ViewStates.Invisible;
return;
}
for (int i = 0; i < órarend.Órakezdetek.Length - 1; i++)
{
var vége = órarend.Órakezdetek[i].Add(new TimeSpan(0, 45, 0));
if (most > órarend.Órakezdetek[i])
{
if (most < vége)
{
kezdveg.Text = "Kicsengetés: " + (vége - most).ToString("hh\\:mm\\:ss");
talált = true;
}
else
continue;
}
else
{
kezdveg.Text = "Becsengetés: " + (órarend.Órakezdetek[i] - most).ToString("hh\\:mm\\:ss");
talált = true;
kovora.Visibility = ViewStates.Invisible;
}
int x = (int)DateTime.Today.DayOfWeek - 1;
if (x == -1) //Vasárnap
break;
Óra óra;
if (x < 6 && (óra = órarend.ÓrákAHét[x][i]) != null)
{
kovora.Text = "Következő óra: " + óra.EgyediNév + "\n" + óra.Terem + "\n" + óra.Tanár.Név + "\n" + óra.Csoportok.Aggregate((a, b) => a + ", " + b);
kovora.Visibility = ViewStates.Visible;
}
else
kovora.Visibility = ViewStates.Invisible;
break;
}
if (!talált)
{
kezdveg.Text = "Nincs több óra ma";
kovora.Visibility = ViewStates.Invisible;
}
kovora.Visibility = e.KövetkezőÓra == null ? ViewStates.Invisible : ViewStates.Visible;
kovora.Text = e.KövetkezőÓra ?? "";
kezdveg.Visibility = e.HátralévőIdő == null ? ViewStates.Invisible : ViewStates.Visible;
kezdveg.Text = e.HátralévőIdő ?? "";
});
}
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (resultCode == Result.Canceled)
return;
int index = data.Extras.GetBoolean("add") ? API.Órarendek.Count - 1 : data.Extras.GetInt("index");
if (requestCode == EDIT_ADD_ACT_REQUEST)
{
if (resultCode == Result.Canceled)
return;
int index = data.Extras.GetBoolean("add") ? API.Órarendek.Count - 1 : data.Extras.GetInt("index");
if (!data.Extras.GetBoolean("deleted"))
ÓrarendFrissítés(API.Órarendek[index]);
ÓrarendFrissítés(false, API.Órarendek[index]);
else
{
órarend = null;
API.ÓrarendKiválasztásTörlése();
órarendfrissítés();
}
órarendlistafrissítés();
}
else if (requestCode == SETTINGS_ACT_REQUEST)
{
if (data?.Extras?.GetBoolean("offsetchanged") ?? false)
ÓrarendFrissítés(false);
Recreate();
}
}
public override void OnWindowFocusChanged(bool hasFocus)
{
base.OnWindowFocusChanged(hasFocus);
API.Fókusz = hasFocus;
if (!hasFocus)
return;
MaiNaphozGörgetés();
}
private void MaiNaphozGörgetés()
{
var table = FindViewById<TableLayout>(Resource.Id.tableLayout1);
if (table.ChildCount == 0)
return;
var cell = (table.GetChildAt(0) as ViewGroup).GetChildAt((int)API.MaiNap);
FindViewById<HorizontalScrollView>(Resource.Id.horizontalView).SmoothScrollTo(Math.Max(cell.Left - (FindViewById(Resource.Id.container).Width - cell.Width) / 2, 0), 0);
}
}
}

View file

@ -55,15 +55,21 @@
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ActivityBase.cs" />
<Compile Include="EditActivity.cs" />
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SettingsActivity.cs" />
</ItemGroup>
<ItemGroup>
<None Include="GettingStarted.Xamarin" />
<None Include="packages.config" />
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
<AndroidResource Include="Resources\layout\MainLayout.axml">
@ -75,6 +81,7 @@
<AndroidResource Include="Resources\layout\EditLayout.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<AndroidResource Include="Resources\menu\ora_menu.axml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\Strings.xml" />
@ -117,15 +124,30 @@
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\cell_shape_removed_light.xml">
<AndroidResource Include="Resources\xml\preferences.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\cell_shape_dark.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\cell_shape_added_light.xml">
<AndroidResource Include="Resources\drawable\cell_shape_selected_dark.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\ic_add_white_24dp.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\ic_autorenew_white_24dp.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\ic_create_white_24dp.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\ic_settings_white_24dp.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
@ -134,4 +156,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.github.norbipeti.orarend" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" />
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.github.norbipeti.orarend" android:versionName="1.2" android:installLocation="auto" android:versionCode="2">
<uses-sdk android:minSdkVersion="11" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:label="Orarend"></application>
</manifest>

View file

@ -45,13 +45,13 @@ namespace OrarendAndroidApp
{
// aapt resource value: 0x7f020000
public const int cell_shape_added_light = 2130837504;
public const int cell_shape_dark = 2130837504;
// aapt resource value: 0x7f020001
public const int cell_shape_light = 2130837505;
// aapt resource value: 0x7f020002
public const int cell_shape_removed_light = 2130837506;
public const int cell_shape_selected_dark = 2130837506;
// aapt resource value: 0x7f020003
public const int cell_shape_selected_light = 2130837507;
@ -60,16 +60,28 @@ namespace OrarendAndroidApp
public const int ic_add_black_24dp = 2130837508;
// aapt resource value: 0x7f020005
public const int ic_autorenew_black_24dp = 2130837509;
public const int ic_add_white_24dp = 2130837509;
// aapt resource value: 0x7f020006
public const int ic_create_black_24dp = 2130837510;
public const int ic_autorenew_black_24dp = 2130837510;
// aapt resource value: 0x7f020007
public const int ic_settings_black_24dp = 2130837511;
public const int ic_autorenew_white_24dp = 2130837511;
// aapt resource value: 0x7f020008
public const int Icon = 2130837512;
public const int ic_create_black_24dp = 2130837512;
// aapt resource value: 0x7f020009
public const int ic_create_white_24dp = 2130837513;
// aapt resource value: 0x7f02000a
public const int ic_settings_black_24dp = 2130837514;
// aapt resource value: 0x7f02000b
public const int ic_settings_white_24dp = 2130837515;
// aapt resource value: 0x7f02000c
public const int Icon = 2130837516;
static Drawable()
{
@ -84,83 +96,83 @@ namespace OrarendAndroidApp
public partial class Id
{
// aapt resource value: 0x7f060009
public const int ScrollView01 = 2131099657;
// aapt resource value: 0x7f07000d
public const int ScrollView01 = 2131165197;
// aapt resource value: 0x7f06000d
public const int ScrollView02 = 2131099661;
// aapt resource value: 0x7f07000a
public const int ScrollView02 = 2131165194;
// aapt resource value: 0x7f060013
public const int actionMenuView1 = 2131099667;
// aapt resource value: 0x7f070009
public const int container = 2131165193;
// aapt resource value: 0x7f060005
public const int csoportokEditText = 2131099653;
// aapt resource value: 0x7f070005
public const int csoportokEditText = 2131165189;
// aapt resource value: 0x7f060008
public const int deleteButton = 2131099656;
// aapt resource value: 0x7f070008
public const int deleteButton = 2131165192;
// aapt resource value: 0x7f06000a
public const int horizontalView = 2131099658;
// aapt resource value: 0x7f070010
public const int helyTV = 2131165200;
// aapt resource value: 0x7f060010
public const int kezdvegTV = 2131099664;
// aapt resource value: 0x7f07000e
public const int horizontalView = 2131165198;
// aapt resource value: 0x7f06000f
public const int kivoraTV = 2131099663;
// aapt resource value: 0x7f070012
public const int kezdvegTV = 2131165202;
// aapt resource value: 0x7f060011
public const int kovoraTV = 2131099665;
// aapt resource value: 0x7f070011
public const int kivoraTV = 2131165201;
// aapt resource value: 0x7f060016
public const int menu_add = 2131099670;
// aapt resource value: 0x7f070013
public const int kovoraTV = 2131165203;
// aapt resource value: 0x7f060017
public const int menu_edit = 2131099671;
// aapt resource value: 0x7f070016
public const int menu_add = 2131165206;
// aapt resource value: 0x7f060019
public const int menu_fullrefresh = 2131099673;
// aapt resource value: 0x7f070017
public const int menu_edit = 2131165207;
// aapt resource value: 0x7f060018
public const int menu_preferences = 2131099672;
// aapt resource value: 0x7f070019
public const int menu_fullrefresh = 2131165209;
// aapt resource value: 0x7f060015
public const int menu_refresh = 2131099669;
// aapt resource value: 0x7f070018
public const int menu_preferences = 2131165208;
// aapt resource value: 0x7f060001
public const int névEditText = 2131099649;
// aapt resource value: 0x7f070015
public const int menu_refresh = 2131165205;
// aapt resource value: 0x7f060012
public const int osztalylistaTV = 2131099666;
// aapt resource value: 0x7f070001
public const int névEditText = 2131165185;
// aapt resource value: 0x7f060003
public const int osztálySpinner = 2131099651;
// aapt resource value: 0x7f070014
public const int osztalylistaTV = 2131165204;
// aapt resource value: 0x7f06000c
public const int progressBar1 = 2131099660;
// aapt resource value: 0x7f070003
public const int osztálySpinner = 2131165187;
// aapt resource value: 0x7f060007
public const int saveButton = 2131099655;
// aapt resource value: 0x7f07000c
public const int progressBar1 = 2131165196;
// aapt resource value: 0x7f06000e
public const int scrollLinearLayout = 2131099662;
// aapt resource value: 0x7f070007
public const int saveButton = 2131165191;
// aapt resource value: 0x7f060014
public const int spinner = 2131099668;
// aapt resource value: 0x7f07000b
public const int scrollLinearLayout = 2131165195;
// aapt resource value: 0x7f06000b
public const int tableLayout1 = 2131099659;
// aapt resource value: 0x7f07000f
public const int tableLayout1 = 2131165199;
// aapt resource value: 0x7f060000
public const int textView1 = 2131099648;
// aapt resource value: 0x7f070000
public const int textView1 = 2131165184;
// aapt resource value: 0x7f060002
public const int textView2 = 2131099650;
// aapt resource value: 0x7f070002
public const int textView2 = 2131165186;
// aapt resource value: 0x7f060004
public const int textView3 = 2131099652;
// aapt resource value: 0x7f070004
public const int textView3 = 2131165188;
// aapt resource value: 0x7f060006
public const int textView4 = 2131099654;
// aapt resource value: 0x7f070006
public const int textView4 = 2131165190;
static Id()
{
@ -197,8 +209,11 @@ namespace OrarendAndroidApp
public partial class Menu
{
// aapt resource value: 0x7f050000
public const int main_menu_light = 2131034112;
// aapt resource value: 0x7f060000
public const int main_menu_light = 2131099648;
// aapt resource value: 0x7f060001
public const int ora_menu = 2131099649;
static Menu()
{
@ -213,11 +228,11 @@ namespace OrarendAndroidApp
public partial class String
{
// aapt resource value: 0x7f040001
public const int ApplicationName = 2130968577;
// aapt resource value: 0x7f050001
public const int ApplicationName = 2131034113;
// aapt resource value: 0x7f040000
public const int Hello = 2130968576;
// aapt resource value: 0x7f050000
public const int Hello = 2131034112;
static String()
{
@ -228,6 +243,22 @@ namespace OrarendAndroidApp
{
}
}
public partial class Xml
{
// aapt resource value: 0x7f040000
public const int preferences = 2130968576;
static Xml()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Xml()
{
}
}
}
}
#pragma warning restore 1591

View file

@ -2,6 +2,6 @@
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape= "rectangle" >
<solid android:color="#eee"/>
<stroke android:width="1dp" android:color="#00d"/>
<solid android:color="#222"/>
<stroke android:width="1dp" android:color="#fff"/>
</shape>

View file

@ -2,6 +2,6 @@
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape= "rectangle" >
<solid android:color="#eee"/>
<stroke android:width="1dp" android:color="#0d0"/>
<solid android:color="#333"/>
<stroke android:width="1dp" android:color="#fff"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

View file

@ -31,7 +31,7 @@
<Spinner
android:layout_column="1"
android:id="@+id/osztálySpinner"
android:layout_width="fill_parent" />
android:layout_width="500dp" />
</TableRow>
<TableRow>
<TextView

View file

@ -1,42 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:minWidth="25px"
android:minHeight="25px">
<ScrollView
android:id="@+id/ScrollView01"
android:layout_height="wrap_content"
android:scrollbars="horizontal"
android:layout_width="match_parent"
android:layout_marginTop="5dip"
android:scrollbarStyle="outsideInset"
android:fillViewport="true">
<HorizontalScrollView
android:id="@+id/horizontalView"
android:layout_height="wrap_content"
android:scrollbars="horizontal"
android:layout_width="wrap_content"
android:layout_marginTop="5dip">
<TableLayout
android:id="@+id/tableLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="1"
android:isScrollContainer="true">
<ProgressBar
style="@android:attr/progressBarStyleHorizontal"
android:id="@+id/progressBar1"
android:indeterminateTint="#00ffffff"
android:indeterminate="true"
android:indeterminateBehavior="repeat"
android:indeterminateOnly="true"
android:indeterminateTintMode="add"
android:visibility="gone" />
</TableLayout>
</HorizontalScrollView>
</ScrollView>
<ScrollView
android:id="@+id/ScrollView02"
android:layout_height="wrap_content"
@ -52,6 +22,48 @@
android:minWidth="25px"
android:minHeight="25px"
android:id="@+id/scrollLinearLayout">
<ProgressBar
style="@android:attr/progressBarStyleHorizontal"
android:id="@+id/progressBar1"
android:indeterminateTint="#00ffffff"
android:indeterminate="true"
android:indeterminateBehavior="repeat"
android:indeterminateOnly="true"
android:indeterminateTintMode="add"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:visibility="gone" />
<ScrollView
android:id="@+id/ScrollView01"
android:layout_height="wrap_content"
android:scrollbars="horizontal"
android:layout_width="match_parent"
android:layout_marginTop="5dip"
android:scrollbarStyle="outsideInset"
android:fillViewport="true">
<HorizontalScrollView
android:id="@+id/horizontalView"
android:layout_height="wrap_content"
android:scrollbars="horizontal"
android:layout_width="wrap_content"
android:layout_marginTop="5dip">
<TableLayout
android:id="@+id/tableLayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="1"
android:isScrollContainer="true" />
</HorizontalScrollView>
</ScrollView>
<TextView
android:id="@+id/helyTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Helyettesítés"
android:textSize="14sp"
android:textStyle="bold"
android:visibility="gone"
android:textColor="#FF0000" />
<TextView
android:id="@+id/kivoraTV"
android:layout_width="wrap_content"
@ -85,10 +97,4 @@
android:visibility="gone" />
</LinearLayout>
</ScrollView>
<ActionMenuView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/actionMenuView1" />
</LinearLayout>

View file

@ -1,13 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/spinner"
<!-- <item android:id="@+id/spinner"
android:title="will be replaced anyway"
android:showAsAction="always"
android:actionViewClass="android.widget.Spinner" />
android:actionViewClass="android.widget.Spinner"
android:layout_width="fill_parent" /> -->
<item
android:id="@+id/menu_refresh"
android:icon="@drawable/ic_autorenew_black_24dp"
android:showAsAction="always"
android:showAsAction="always"
android:title="Frissítés" />
<item
android:id="@+id/menu_add"

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_refresh"
android:title="Frissítés" />
<item
android:id="@+id/menu_add"
android:title="Hozzáadás" />
<item
android:id="@+id/menu_edit"
android:title="Szerkesztés" />
<item
android:id="@+id/menu_preferences"
android:title="Beállítások" />
<item
android:id="@+id/menu_fullrefresh"
android:title="Órarendfrissítés" />
</menu>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="pref_theme"
android:title="Sötét téma"
android:summary="Sötét téma"
android:defaultValue="false" />
<Preference
android:key="pref_commonnames"
android:title="Gyakori óranevek"
android:summary="Gyakori óranevek használata" />
<EditTextPreference
android:key="pref_offset"
android:title="Óra eltolás"
android:summary="Pl. ha 1, akkor az első óra 8:15-kor kezdődik."
android:defaultValue="0"
android:numeric="integer" />
</PreferenceScreen>

View file

@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Preferences;
using Orarend;
using System.Security;
namespace OrarendAndroidApp
{
[Activity(Label = "Beállítások", Theme = "@android:style/Theme.Holo.Light")]
public class SettingsActivity : PreferenceActivity, ISharedPreferencesOnSharedPreferenceChangeListener, Preference.IOnPreferenceClickListener
{
protected override void OnCreate(Bundle savedInstanceState)
{
ActivityBase.SetTheme(this);
/*var settings = PreferenceManager.GetDefaultSharedPreferences(this);
bool darktheme = settings.GetBoolean("pref_theme", false);
//SetTheme(darktheme ? Android.Resource.Style.ThemeDeviceDefault : Android.Resource.Style.ThemeDeviceDefaultLight);
SetTheme(darktheme ? Android.Resource.Style.ThemeHolo : Android.Resource.Style.ThemeHoloLight);*/
base.OnCreate(savedInstanceState);
#pragma warning disable CS0618 // Type or member is obsolete
AddPreferencesFromResource(Resource.Xml.preferences);
FindPreference("pref_commonnames").OnPreferenceClickListener = this;
#pragma warning restore CS0618 // Type or member is obsolete
PreferenceManager.SetDefaultValues(this, Resource.Xml.preferences, false);
}
private Intent intent;
public void OnSharedPreferenceChanged(ISharedPreferences sharedPreferences, string key)
{
switch (key)
{
case "pref_theme":
Recreate();
break;
case "pref_commonnames":
API.Beállítások.UseCommonNames();
Toast.MakeText(this, "Óranevek frissítve", ToastLength.Short).Show();
break;
case "pref_offset":
API.Beállítások.ÓraOffset = sbyte.Parse(sharedPreferences.GetString(key, "0"));
intent = new Intent(Intent);
intent.PutExtra("offsetchanged", true);
SetResult(Result.Ok, intent);
break;
}
}
protected override void OnResume()
{
base.OnResume();
PreferenceManager.GetDefaultSharedPreferences(this).RegisterOnSharedPreferenceChangeListener(this);
}
protected override void OnPause()
{
base.OnPause();
PreferenceManager.GetDefaultSharedPreferences(this).UnregisterOnSharedPreferenceChangeListener(this);
}
public override void OnBackPressed()
{
SetResult(Result.Ok, intent);
//base.OnBackPressed();
Finish();
}
public bool OnPreferenceClick(Preference preference)
{
if (preference.Key == "pref_commonnames")
{
API.Beállítások.UseCommonNames();
Toast.MakeText(this, "Óranevek frissítve", ToastLength.Short).Show();
}
return true;
}
}
}

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.ValueTuple" version="4.4.0" targetFramework="monoandroid60" />
</packages>

6
README.md Normal file
View file

@ -0,0 +1,6 @@
# Orarend
A school schedule app written in C# using Xamarin.
This app can obtain the schedule automatically from the school's website and update it as needed. Any temporary changes are marked red.
It downloads the site HTML and uses regex to fix some issues that the parser can't handle correctly and then parses the code.