1
0
mirror of https://github.com/XFox111/GUTSchedule.git synced 2026-04-22 06:58:01 +03:00

Merge pull request #20 from XFox111/uwp-version

[14-Mar-2020] Major project update
This commit is contained in:
Michael Gordeev
2020-03-14 10:23:43 +03:00
committed by GitHub
137 changed files with 6195 additions and 1519 deletions
+4 -3
View File
@@ -25,9 +25,10 @@ If applicable, add screenshots to help explain your problem.
### Environment ### Environment
Please complete the following information: Please complete the following information:
- Device: [e.g. Google Pixel 3 XL] - Platform: [e.g. Windows 10 Pro]
- Android OS version: [e.g. 7.1] - Device: [e.g. Microsoft Surface Pro 6]
- Application version: [e.g. 1.0.1] - OS version: [e.g. 1909 (10.0.18363)]
- Application version: [e.g. 20200202.1]
### Additional context ### Additional context
Add any other context about the problem here. Add any other context about the problem here.
+34 -10
View File
@@ -87,13 +87,26 @@ If you are interested in writing code to fix issues or implement new awesome fea
git clone https://github.com/xfox111/GUTSchedule.git git clone https://github.com/xfox111/GUTSchedule.git
``` ```
2. Open `GUT.Schedule/GUT.Schedule.sln` using [Microsoft Visual Studio](https://visualstudio.microsoft.com/) 2019 or later 2. Open `GUT.Schedule/GUT.Schedule.sln` using [Microsoft Visual Studio](https://visualstudio.microsoft.com/) 2019 or later
- Make sure you have properly installed and congigured [Xamarin.Android](https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/) environment - Make sure you have properly installed and congigured [Xamarin.Android](https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/) and UWP development environments
3. On the VS toolbar choose build configuration:
**Android**
1. In `Solution Explorer` right-click `GUTSchedule.Droid` project and click `Set as StartUp Project`
2. On the VS toolbar choose build configuration:
- `Debug` for building and deploying test version of the app - `Debug` for building and deploying test version of the app
- `Release` for building final version of application and creating AppBundle package (.aab) - `Release` for building final version of application and creating AppBundle package (.aab)
- `Release (APK)` for building final version of application and creating Android package fike (.apk) - `Release (APK)` for building final version of application and creating Android package fike (.apk)
4. To ensure that code compiles go to `Build -> Build Solution` 3. To ensure that code compiles go to `Build -> Build Solution`
5. [Debug application](https://docs.microsoft.com/en-us/xamarin/android/deploy-test/debugging/) on an actual device or Android Emulator 4. [Debug application](https://docs.microsoft.com/en-us/xamarin/android/deploy-test/debugging/) on an actual device or Android Emulator
**UWP**
1. In `Solution Explorer` right-click `GUTSchedule.UWP (Universal Windows)` project and click `Set as StartUp Project`
2. On the VS toolbar choose build configuration:
- `Debug` for building and deploying test version of the app
- `Release` for building final version of application and creating Appx packages
3. To ensure that code compiles go to `Build -> Build Solution`
4. [Debug application](https://docs.microsoft.com/en-us/windows/uwp/debug-test-perf/deploying-and-debugging-uwp-apps) on your machine or Windows Device Emulator
### Development workflow ### Development workflow
This section represents how contributors should interact with codebase implementing features and fixing bugs This section represents how contributors should interact with codebase implementing features and fixing bugs
@@ -241,19 +254,30 @@ To avoid multiple pull requests resolving the same issue, let others know you ar
### Contributing to translations ### Contributing to translations
If you want to help us to translate this application into other languages you can do it making these steps: If you want to help us to translate this application into other languages you can do it making these steps:
1. Navigate to `GUT.Schedule/GUT.Schedule/Resources` **Android**
1. Navigate to `GUT.Schedule/GUTSchedule.Droid/Resources`
2. Create new folder named `values-lc` where `lc` is locale language. 2. Create new folder named `values-lc` where `lc` is locale language.
Folder name examples: Folder name examples:
- `values-uk` for Ukrainian - `values-uk` for Ukrainian
- `values-be` for Belarusian - `values-be` for Belarusian
- `values-ru` for Russian - `values-ru` for Russian
> **Note** that we only accept region neutral localizations (e.g. pull request with `values-en-rUS` (English (United States)) folder will be rejected whether PR with `values-en` (English (Invarian Country)) folder will be accepted).
For reference, here is a [list of Java locales](https://www.oracle.com/technetwork/java/javase/locales-137662.html) and [Android-supported locales via StackOverflow](https://stackoverflow.com/questions/7973023/what-is-the-list-of-supported-languages-locales-on-android). For reference, here is a [list of Java locales](https://www.oracle.com/technetwork/java/javase/locales-137662.html) and [Android-supported locales via StackOverflow](https://stackoverflow.com/questions/7973023/what-is-the-list-of-supported-languages-locales-on-android).
3. In the folder copy `strings.xml` file from `GUT.Schedule/GUT.Schedule/Resources/values`
3. In the folder copy `strings.xml` file from `GUT.Schedule/GUTSchedule.Droid/Resources/values`
**UWP**
1. Navigate to `GUT.Schedule/GUTSchedule.UWP/Strings`
2. Clone the folder you want to base your localization on and change its name to match desired localization language. See [Globalization and localization](https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/globalizing-portal) for more information
3. Open `.resw` files from the folder in Visual Studio or other text editor
***
4. Edit localization strings 4. Edit localization strings
5. Commit changes and create a pull request 5. Commit changes and create a pull request
> **Note** that we only accept region neutral localizations (e.g. pull request with `values-en-rUS` (English (United States)) folder will be rejected whether PR with `values-en` (English) folder will be accepted).
### Submitting pull requests ### Submitting pull requests
To enable us to quickly review and accept your pull requests, always create one pull request per issue and [link the issue in the pull request](https://github.com/blog/957-introducing-issue-mentions). Never merge multiple requests in one unless they have the same root cause. Be sure to follow our [Coding Guidelines](#coding-guidelines) and keep code changes as small as possible. Avoid pure formatting changes to code that has not been modified otherwise. Pull requests should contain tests whenever possible. Fill pull request content according to its template. Deviations from template are not recommended To enable us to quickly review and accept your pull requests, always create one pull request per issue and [link the issue in the pull request](https://github.com/blog/957-introducing-issue-mentions). Never merge multiple requests in one unless they have the same root cause. Be sure to follow our [Coding Guidelines](#coding-guidelines) and keep code changes as small as possible. Avoid pure formatting changes to code that has not been modified otherwise. Pull requests should contain tests whenever possible. Fill pull request content according to its template. Deviations from template are not recommended
-31
View File
@@ -1,31 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29609.76
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GUT.Schedule", "GUT.Schedule\GUT.Schedule.csproj", "{A0471165-37F5-4309-8A92-42F1A6589EEE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release (APK)|Any CPU = Release (APK)|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A0471165-37F5-4309-8A92-42F1A6589EEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0471165-37F5-4309-8A92-42F1A6589EEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0471165-37F5-4309-8A92-42F1A6589EEE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{A0471165-37F5-4309-8A92-42F1A6589EEE}.Release (APK)|Any CPU.ActiveCfg = Release (APK)|Any CPU
{A0471165-37F5-4309-8A92-42F1A6589EEE}.Release (APK)|Any CPU.Build.0 = Release (APK)|Any CPU
{A0471165-37F5-4309-8A92-42F1A6589EEE}.Release (APK)|Any CPU.Deploy.0 = Release (APK)|Any CPU
{A0471165-37F5-4309-8A92-42F1A6589EEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0471165-37F5-4309-8A92-42F1A6589EEE}.Release|Any CPU.Build.0 = Release|Any CPU
{A0471165-37F5-4309-8A92-42F1A6589EEE}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {456DD1C4-9BC4-4D79-A999-8F85492E7C20}
EndGlobalSection
EndGlobal
@@ -1,86 +0,0 @@
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Support.V4.Text;
using Android.Support.V7.App;
using Android.Text.Method;
using Android.Widget;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
namespace GUT.Schedule.Activities
{
[Activity(Label = "@string/aboutTitle")]
public class AboutActivity : AppCompatActivity
{
protected override async void OnCreate(Bundle savedInstanceState)
{
(string name, string handle, string link)[] contacts = new (string, string, string)[]
{
(Resources.GetText(Resource.String.websiteContact), "https://xfox111.net", "https://xfox111.net"),
(Resources.GetText(Resource.String.twitterContact), "@xfox111", "https://twitter.com/xfox111"),
(Resources.GetText(Resource.String.vkontakteContact), "@xfox.mike", "https://vk.com/xfox.mike"),
("LinkedIn", "@xfox", "https://linkedin.com/in/xfox"),
("GitHub", "@xfox111", "https://github.com/xfox111"),
};
(string name, string link)[] links = new (string, string)[]
{
(Resources.GetText(Resource.String.privacyPolicyLink), "https://xfox111.net/Projects/GUTSchedule/PrivacyPolicy.txt"),
("General Public License v3", "https://www.gnu.org/licenses/gpl-3.0"),
(Resources.GetText(Resource.String.repositoryLink), "https://github.com/xfox111/gutschedule"),
(Resources.GetText(Resource.String.notsLink), "http://tios.spbgut.ru/index.php"),
(Resources.GetText(Resource.String.sutLink), "https://sut.ru"),
};
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.About);
PackageInfo version = PackageManager.GetPackageInfo(PackageName, PackageInfoFlags.MatchAll);
FindViewById<TextView>(Resource.Id.version).Text = $"v{version.VersionName} (ci-id #{version.VersionCode})";
FindViewById<Button>(Resource.Id.feedback).Click += (s, e) =>
StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("mailto:feedback@xfox111.net")));
FindViewById<TextView>(Resource.Id.contacts).SetText(
HtmlCompat.FromHtml(string.Join("<br />", contacts.Select(i => $"<span>{i.name}:</span> <a href=\"{i.link}\">{i.handle}</a>")), HtmlCompat.FromHtmlModeLegacy),
TextView.BufferType.Normal);
FindViewById<TextView>(Resource.Id.contacts).MovementMethod = LinkMovementMethod.Instance;
FindViewById<TextView>(Resource.Id.links).SetText(
HtmlCompat.FromHtml(string.Join("<br />", links.Select(i => $"<a href=\"{i.link}\">{i.name}</a>")), HtmlCompat.FromHtmlModeLegacy),
TextView.BufferType.Normal);
FindViewById<TextView>(Resource.Id.links).MovementMethod = LinkMovementMethod.Instance;
List<string> contributors = new List<string>();
try
{
using HttpClient client = new HttpClient();
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/xfox111/gutschedule/contributors");
request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0");
HttpResponseMessage response = await client.SendAsync(request);
string resposeContent = await response.Content.ReadAsStringAsync();
dynamic parsedResponse = JsonConvert.DeserializeObject(resposeContent);
foreach (var i in parsedResponse)
if (i.type == "User" && ((string)i.login).ToLower() != "xfox111")
contributors.Add((string)i.login);
}
finally
{
if (contributors.Count > 0)
{
FindViewById<TextView>(Resource.Id.contributors).SetText(
HtmlCompat.FromHtml(string.Join(", ", contributors.Select(i => $"<a href=\"https://github.com/{i}\">@{i}</a>")), HtmlCompat.FromHtmlModeLegacy),
TextView.BufferType.Normal);
FindViewById<TextView>(Resource.Id.contributors).MovementMethod = LinkMovementMethod.Instance;
FindViewById<TextView>(Resource.Id.contributorsTitle).Visibility = Android.Views.ViewStates.Visible;
FindViewById<TextView>(Resource.Id.contributors).Visibility = Android.Views.ViewStates.Visible;
}
}
}
}
}
@@ -1,96 +0,0 @@
using Android.App;
using Android.OS;
using Android.Widget;
using GUT.Schedule.Models;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace GUT.Schedule.Activities
{
/// <summary>
/// Shows status of schedule export process
/// </summary>
[Activity(Theme = "@style/AppTheme.Light.SplashScreen")]
public class ExportActivity : Activity
{
TextView status;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Export);
status = FindViewById<TextView>(Resource.Id.status);
Export();
}
private async void Export()
{
try
{
if(Data.DataSet.IsProfessor == true)
status.Text = Resources.GetText(Resource.String.potatoLoadingStatus); // For some reason professors' schedule loads much slower
else
status.Text = Resources.GetText(Resource.String.loadingStatus);
if (Data.DataSet.HttpClient != null)
{
List<CabinetSubject> schedule = new List<CabinetSubject>();
for(DateTime d = Data.StartDate; d <= Data.EndDate; d = d.AddMonths(1))
schedule.AddRange(await Parser.GetCabinetSchedule(Data.DataSet.HttpClient, d, false)); // Even though the user can be professor he can be also PhD student (and have his student schedule)
if(Data.DataSet.IsProfessor == true)
for (DateTime d = Data.StartDate; d <= Data.EndDate; d = d.AddMonths(1))
schedule.AddRange(await Parser.GetCabinetSchedule(Data.DataSet.HttpClient, d, true));
schedule = schedule.FindAll(i => i.StartTime.Date >= Data.StartDate && i.StartTime.Date <= Data.EndDate); // Filtering schedule according to export range
status.Text = Resources.GetText(Resource.String.calendarExportStatus);
Calendar.Export(schedule);
}
else
{
List<Subject> schedule = await Parser.LoadSchedule();
schedule = schedule.FindAll(i => i.StartTime.Date >= Data.StartDate && i.StartTime.Date <= Data.EndDate); // Filtering schedule according to export range
status.Text = Resources.GetText(Resource.String.calendarExportStatus);
Calendar.Export(schedule);
}
status.Text = Resources.GetText(Resource.String.doneStatus);
await Task.Delay(1000);
}
catch (HttpRequestException e)
{
Android.Support.V7.App.AlertDialog.Builder builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(Resources.GetText(Resource.String.connectionFailMessage))
.SetTitle(e.Message)
.SetPositiveButton("ОК", (s, e) => base.OnBackPressed())
.SetNegativeButton(Resources.GetText(Resource.String.repeat), (s, e) => Export());
Android.Support.V7.App.AlertDialog dialog = builder.Create();
dialog.Show();
return;
}
catch (Exception e)
{
Android.Support.V7.App.AlertDialog.Builder builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(e.Message)
.SetTitle(e.GetType().ToString())
.SetPositiveButton("ОК", (s, e) => base.OnBackPressed());
Android.Support.V7.App.AlertDialog dialog = builder.Create();
dialog.Show();
return;
}
base.OnBackPressed(); // Navigates back to main activity (always because I don't allow backward navigation)
}
public override void OnBackPressed() { } // Disables back button
}
}
@@ -1,353 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Preferences;
using Android.Support.V4.Text;
using Android.Support.V7.App;
using Android.Text.Method;
using Android.Views;
using Android.Widget;
using AngleSharp.Html.Dom;
using AngleSharp.Html.Parser;
using GUT.Schedule.Models;
namespace GUT.Schedule.Activities
{
[Activity]
public class MainActivity : AppCompatActivity
{
Button start, end, export;
Button forDay, forWeek, forMonth, forSemester;
Spinner faculty, course, group, reminder, calendar;
CheckBox groupTitle, authorize;
TextView error;
LinearLayout studentParams, profParams;
EditText email, password;
ISharedPreferences prefs;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
PackageInfo version = PackageManager.GetPackageInfo(PackageName, PackageInfoFlags.MatchAll);
FindViewById<TextView>(Resource.Id.version).Text = $"v{version.VersionName} (ci-id #{version.VersionCode})";
prefs = PreferenceManager.GetDefaultSharedPreferences(this);
AssignVariables();
faculty.SetList(this, Data.Faculties.Select(i => i.Name));
int s = Data.Faculties.FindIndex(i => i.Id == prefs.GetString("Faculty", "-123"));
faculty.SetSelection(s == -1 ? 0 : s);
course.SetList(this, "1234".ToCharArray());
course.SetSelection(prefs.GetInt("Course", 0)); // IDK why but this shit triggers events anyway (even if they are set in the next line. It seem to be that there's some asynchronous shit somewhere there)
// P.S. Fuck Android
AddEvents();
// Settings spinners' dropdown lists content
reminder.SetList(this, new[]
{
Resources.GetText(Resource.String.noReminderOption),
Resources.GetText(Resource.String.inTimeReminderOption),
Resources.GetText(Resource.String.fiveMinuteReminderOption),
Resources.GetText(Resource.String.tenMinuteReminderOption)
});
reminder.SetSelection(prefs.GetInt("Reminder", 0));
calendar.SetList(this, Calendar.Calendars.Select(i => i.Name));
s = Calendar.Calendars.FindIndex(i => i.Id == prefs.GetString("Calendar", "-123"));
calendar.SetSelection(s == -1 ? 0 : s);
end.Text = Data.EndDate.ToShortDateString();
start.Text = Data.StartDate.ToShortDateString();
groupTitle.Checked = prefs.GetBoolean("AddGroupToHeader", false);
authorize.Checked = prefs.GetBoolean("Authorize", true);
email.Text = prefs.GetString("email", "");
password.Text = prefs.GetString("password", "");
}
private async void Export_Click(object sender, EventArgs e)
{
error.Visibility = ViewStates.Gone;
if (Data.StartDate > Data.EndDate)
{
error.Text = Resources.GetText(Resource.String.invalidDateRangeError);
error.Visibility = ViewStates.Visible;
return;
}
HttpClient client = null;
bool? isProf = null;
if(authorize.Checked)
{
Toast.MakeText(ApplicationContext, Resources.GetText(Resource.String.authorizationState), ToastLength.Short).Show();
if (string.IsNullOrWhiteSpace(email.Text) || string.IsNullOrWhiteSpace(password.Text))
{
error.Text = Resources.GetText(Resource.String.invalidAuthorizationError);
error.Visibility = ViewStates.Visible;
return;
}
export.Enabled = false;
client = new HttpClient();
await client.GetAsync("https://cabs.itut.ru/cabinet/");
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://cabs.itut.ru/cabinet/lib/autentificationok.php");
request.SetContent(
("users", email.Text),
("parole", password.Text));
HttpResponseMessage response = await client.SendAsync(request);
string responseContent = await response.GetString();
export.Enabled = true;
if (!response.IsSuccessStatusCode)
{
error.Text = $"{Resources.GetText(Resource.String.authorizationError)}: {response.StatusCode}: {responseContent}";
error.Visibility = ViewStates.Visible;
return;
}
if (!responseContent.StartsWith("1", StringComparison.OrdinalIgnoreCase))
{
error.Text = $"{Resources.GetText(Resource.String.invalidCredentialError)} ({string.Join("; ", responseContent.Replace("error=", "", StringComparison.OrdinalIgnoreCase).Split('|'))})";
error.Visibility = ViewStates.Visible;
return;
}
export.Enabled = false;
HttpResponseMessage verificationResponse = await client.GetAsync("https://cabs.itut.ru/cabinet/?login=yes");
export.Enabled = true;
IHtmlDocument doc = new HtmlParser().ParseDocument(await verificationResponse.GetString());
if (doc.QuerySelectorAll("option").Any(i => i.TextContent.Contains("Сотрудник")))
isProf = true;
else
isProf = false;
Data.Groups = null;
// Если ты это читаешь и у тебя возникли вопросы по типу "А какого хуя творится в коде ниже?!", то во-первых:
// According to this SO thread: https://stackoverflow.com/questions/1925486/android-storing-username-and-password
// I consider Preferences as safe enough method for storing credentials
// А во-вторых, даже такой казалось бы небезопасный метод хранения учетных данных в сто раз надежнее того дерьма,
// что творится на серверах Бонча (я не шучу, там все ОЧЕНЬ плохо)
// Ну и в-третьих: Андроид - это пиздец и настоящий ад разработчика. И если бы была моя воля, я бы под него никогда не писал #FuckAndroid
// З.Ы. Помнишь про второй пункт? Так вот, если ты используешь такой же пароль как в ЛК где-то еще, настоятельно рекомендую его поменять
PreferenceManager.GetDefaultSharedPreferences(this).Edit().PutString("email", email.Text).Apply();
PreferenceManager.GetDefaultSharedPreferences(this).Edit().PutString("password", password.Text).Apply();
}
else
{
if(Data.Groups.Count < 1)
{
error.Text = Resources.GetText(Resource.String.groupSelectionError);
error.Visibility = ViewStates.Visible;
return;
}
}
// Forming export parameters
Data.DataSet = new DataSet
{
Faculty = Data.Faculties[faculty.SelectedItemPosition].Id,
Group = Data.Groups?[group.SelectedItemPosition].Id,
Course = course.SelectedItemPosition + 1,
AddGroupToTitle = groupTitle.Checked,
Calendar = Calendar.Calendars[calendar.SelectedItemPosition].Id,
Reminder = (reminder.SelectedItemPosition - 1) * 5,
HttpClient = client,
IsProfessor = isProf
};
StartActivity(new Intent(this, typeof(ExportActivity)));
}
private async void End_Click(object sender, EventArgs e)
{
Data.EndDate = await new DatePickerFragment().GetDate(SupportFragmentManager, Data.EndDate);
end.Text = Data.EndDate.ToShortDateString();
}
private async void Start_Click(object sender, EventArgs e)
{
Data.StartDate = await new DatePickerFragment().GetDate(SupportFragmentManager, Data.StartDate);
start.Text = Data.StartDate.ToShortDateString();
}
private async void UpdateGroupsList()
{
if (course.SelectedItem == null)
return;
await Parser.LoadGroups(Data.Faculties[faculty.SelectedItemPosition].Id, course.SelectedItemPosition + 1);
group.SetList(this, Data.Groups.Select(i => i.Name));
int s = Data.Groups?.FindIndex(i => i.Id == prefs.GetString("Group", "-123")) ?? 0;
group.SetSelection(s == -1 ? 0 : s);
}
private void SetDate(int days)
{
Data.EndDate = Data.StartDate.AddDays(days);
end.Text = Data.EndDate.ToShortDateString();
}
#region Init stuff
private void AssignVariables()
{
start = FindViewById<Button>(Resource.Id.start);
end = FindViewById<Button>(Resource.Id.end);
export = FindViewById<Button>(Resource.Id.export);
forDay = FindViewById<Button>(Resource.Id.forDay);
forWeek = FindViewById<Button>(Resource.Id.forWeek);
forMonth = FindViewById<Button>(Resource.Id.forMonth);
forSemester = FindViewById<Button>(Resource.Id.forSemester);
faculty = FindViewById<Spinner>(Resource.Id.faculty);
course = FindViewById<Spinner>(Resource.Id.course);
group = FindViewById<Spinner>(Resource.Id.group);
reminder = FindViewById<Spinner>(Resource.Id.reminder);
calendar = FindViewById<Spinner>(Resource.Id.calendar);
error = FindViewById<TextView>(Resource.Id.error);
groupTitle = FindViewById<CheckBox>(Resource.Id.groupTitle);
authorize = FindViewById<CheckBox>(Resource.Id.authorization);
studentParams = FindViewById<LinearLayout>(Resource.Id.studentParams);
profParams = FindViewById<LinearLayout>(Resource.Id.professorParams);
email = FindViewById<EditText>(Resource.Id.email);
password = FindViewById<EditText>(Resource.Id.password);
}
private void AddEvents()
{
faculty.ItemSelected += (s, e) =>
{
prefs.Edit().PutString("Faculty", Data.Faculties[e.Position].Id).Apply();
UpdateGroupsList();
};
course.ItemSelected += (s, e) =>
{
prefs.Edit().PutInt("Course", e.Position).Apply();
UpdateGroupsList();
};
authorize.CheckedChange += (s, e) =>
{
prefs.Edit().PutBoolean("Authorize", e.IsChecked).Apply();
if (e.IsChecked)
{
studentParams.Visibility = ViewStates.Gone;
profParams.Visibility = ViewStates.Visible;
}
else
{
studentParams.Visibility = ViewStates.Visible;
profParams.Visibility = ViewStates.Gone;
}
};
calendar.ItemSelected += (s, e) =>
prefs.Edit().PutString("Calendar", Calendar.Calendars[e.Position].Id).Apply();
reminder.ItemSelected += (s, e) =>
prefs.Edit().PutInt("Reminder", e.Position).Apply();
group.ItemSelected += (s, e) =>
prefs.Edit().PutString("Group", Data.Groups[e.Position].Id).Apply();
groupTitle.Click += (s, e) =>
prefs.Edit().PutBoolean("AddGroupToHeader", groupTitle.Checked).Apply();
forDay.Click += (s, e) => SetDate(0);
forWeek.Click += (s, e) => SetDate(6);
forMonth.Click += (s, e) => SetDate(30);
forSemester.Click += (s, e) =>
{
Data.EndDate = DateTime.Today.Month > 8 ? new DateTime(DateTime.Today.Year + 1, 1, 1) : new DateTime(DateTime.Today.Year, 8, 31);
end.Text = Data.EndDate.ToShortDateString();
};
start.Click += Start_Click;
end.Click += End_Click;
export.Click += Export_Click;
}
#endregion
#region Menu stuff
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.MainContextMenu, menu);
return true;
}
public void Clear(bool keepPrevious = true)
{
try
{
Toast.MakeText(ApplicationContext, Resources.GetText(Resource.String.clearingStatus), ToastLength.Short).Show();
Calendar.Clear(keepPrevious);
Toast.MakeText(ApplicationContext, Resources.GetText(Resource.String.doneStatus), ToastLength.Short).Show();
}
catch (Exception e)
{
Android.Support.V7.App.AlertDialog.Builder builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(e.Message)
.SetTitle(e.GetType().ToString())
.SetPositiveButton("ОК", (IDialogInterfaceOnClickListener)null);
Android.Support.V7.App.AlertDialog dialog = builder.Create();
dialog.Show();
}
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
Android.Support.V7.App.AlertDialog.Builder builder;
Android.Support.V7.App.AlertDialog dialog;
switch (item.ItemId)
{
case Resource.Id.about:
StartActivity(new Intent(this, typeof(AboutActivity)));
return true;
case Resource.Id.email:
StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("mailto:feedback@xfox111.net")));
return true;
case Resource.Id.clear:
builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(Resources.GetText(Resource.String.clearScheduleMessage))
.SetTitle(Resources.GetText(Resource.String.clearScheduleTitle))
.SetPositiveButton(Resources.GetText(Resource.String.clearUpcomingOption), (s, e) => Clear())
.SetNegativeButton(Resources.GetText(Resource.String.clearAllOption), (s, e) => Clear(false))
.SetNeutralButton(Resources.GetText(Resource.String.cancelOption), (IDialogInterfaceOnClickListener)null);
dialog = builder.Create();
dialog.Show();
// Making links clickable
dialog.FindViewById<TextView>(Android.Resource.Id.Message).MovementMethod = LinkMovementMethod.Instance;
return true;
}
return base.OnOptionsItemSelected(item);
}
#endregion
public override void OnBackPressed() =>
FinishAffinity(); // Close application
}
}
@@ -1,112 +0,0 @@
using Android;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using Android.Support.V4.App;
using Android.Support.V4.Content;
using Android.Support.V7.App;
using Android.Widget;
using System;
using System.Linq;
using System.Net.Http;
namespace GUT.Schedule.Activities
{
/// <summary>
/// Splash screen activity. Loads init data
/// </summary>
[Activity(MainLauncher = true, Theme = "@style/AppTheme.Light.SplashScreen")]
public class StartActivity : AppCompatActivity
{
TextView status;
protected override void OnCreate(Bundle savedInstanceState)
{
SetContentView(Resource.Layout.SplashScreen);
base.OnCreate(savedInstanceState);
status = FindViewById<TextView>(Resource.Id.status);
PackageInfo version = PackageManager.GetPackageInfo(PackageName, PackageInfoFlags.MatchAll);
FindViewById<TextView>(Resource.Id.version).Text = $"v{version.VersionName} (ci-id #{version.VersionCode})";
status.Text = Resources.GetText(Resource.String.permissionsCheckStatus);
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteCalendar) != Permission.Granted)
{
if (ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.WriteCalendar))
ShowDialog(Resources.GetText(Resource.String.calendarAccessTitle), Resources.GetText(Resource.String.calendarAccessRationale), RequestPermissions);
else
RequestPermissions();
}
else
Proceed();
}
private async void Proceed()
{
try
{
status.Text = Resources.GetText(Resource.String.calendarLoadingStatus);
Calendar.LoadCalendars();
if (Calendar.Calendars.Count == 0)
{
ShowDialog(Resources.GetText(Resource.String.createCalendarTitle), Resources.GetText(Resource.String.createCalendarMessage));
return;
}
status.Text = Resources.GetText(Resource.String.facultiesLoadingStatus);
await Parser.LoadFaculties();
status.Text = Resources.GetText(Resource.String.offsetDatesLoadingStatus);
using HttpClient client = new HttpClient();
Data.FirstWeekDay = int.Parse(await client.GetStringAsync("https://xfox111.net/schedule_offset.txt"));
}
catch(HttpRequestException e)
{
ShowDialog(e.Message, Resources.GetText(Resource.String.connectionFailMessage), Proceed, FinishAndRemoveTask, Resources.GetText(Resource.String.repeat), Resources.GetText(Resource.String.quit));
return;
}
catch (Exception e)
{
ShowDialog(e.GetType().ToString(), e.Message, FinishAndRemoveTask);
return;
}
StartActivity(new Intent(this, typeof(MainActivity)));
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.All(i => i == Permission.Granted))
Proceed();
else
ShowDialog(Resources.GetText(Resource.String.calendarAccessTitle), Resources.GetText(Resource.String.calendarAccessRationale), RequestPermissions);
}
private void RequestPermissions() =>
ActivityCompat.RequestPermissions(this, new[]
{
Manifest.Permission.ReadCalendar,
Manifest.Permission.WriteCalendar,
Manifest.Permission.Internet
}, 0);
private void ShowDialog(string title, string content, Action posAction = null, Action negAction = null, string posActionLabel = null, string negActionLabel = null)
{
Android.Support.V7.App.AlertDialog.Builder builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(content)
.SetTitle(title).SetPositiveButton(posActionLabel ?? "OK", (s, e) => posAction?.Invoke());
if (negAction != null)
builder.SetNegativeButton(negActionLabel ?? Resources.GetText(Resource.String.close), (s, e) => negAction.Invoke());
Android.Support.V7.App.AlertDialog dialog = builder.Create();
dialog.Show();
}
public override void OnBackPressed() { } // Disables back button
}
}
-154
View File
@@ -1,154 +0,0 @@
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Database;
using Android.Net;
using Android.Provider;
using GUT.Schedule.Models;
using Java.Util;
namespace GUT.Schedule
{
public static class Calendar
{
/// <summary>
/// List of all existing Google calendars on the device
/// </summary>
public static List<(string Id, string Name)> Calendars { get; private set; } = new List<(string Id, string Name)>();
/// <summary>
/// Retrieves all Google Accounts' calendars existing on the device and puts them to <see cref="Calendars"/>
/// </summary>
public static void LoadCalendars()
{
Calendars = new List<(string, string)>(); // Resetting current calendars list
// Building calendar data retrieval projections
Uri calendarsUri = CalendarContract.Calendars.ContentUri;
string[] calendarsProjection = {
CalendarContract.Calendars.InterfaceConsts.Id,
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
CalendarContract.Calendars.InterfaceConsts.AccountName
};
// Retrieving calendars data
ICursor cursor = Application.Context.ContentResolver.Query(calendarsUri, calendarsProjection, null, null, null);
while (cursor.MoveToNext())
Calendars.Add((cursor.GetString(0), $"{cursor.GetString(1)} ({cursor.GetString(2)})"));
cursor.Close();
}
public static void Export(IEnumerable<Subject> schedule)
{
DataSet data = Data.DataSet;
foreach (Subject item in schedule)
{
ContentValues eventValues = new ContentValues();
eventValues.Put(CalendarContract.Events.InterfaceConsts.CalendarId, data.Calendar);
eventValues.Put(CalendarContract.Events.InterfaceConsts.Title, string.Format("{0}.{1} {2} ({3})",
item.Order,
data.AddGroupToTitle ? $" [{item.Group}]" : "",
item.Name,
item.Type));
eventValues.Put(CalendarContract.Events.InterfaceConsts.Description, item.Professor);
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventLocation, string.Join(';', item.Cabinets));
eventValues.Put(CalendarContract.Events.InterfaceConsts.Availability, 0);
eventValues.Put(CalendarContract.Events.InterfaceConsts.HasAlarm, data.Reminder != -5);
// For some reason Google calendars ignore HasAlarm = false and set reminder for 30 minutes. Local calendars don't seem to have this issue
eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtstart, item.StartTime.ToUnixTime());
eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtend, item.EndTime.ToUnixTime());
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone, TimeZone.Default.ID);
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventEndTimezone, TimeZone.Default.ID);
eventValues.Put(CalendarContract.Events.InterfaceConsts.CustomAppPackage, Application.Context.PackageName);
Uri response = Application.Context.ContentResolver.Insert(CalendarContract.Events.ContentUri, eventValues);
// Settings reminder
if(data.Reminder != -5)
{
ContentValues reminderValues = new ContentValues();
reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.EventId, long.Parse(response.LastPathSegment));
reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.Minutes, data.Reminder);
Application.Context.ContentResolver.Insert(CalendarContract.Reminders.ContentUri, reminderValues);
}
}
}
public static void Export(IEnumerable<CabinetSubject> schedule)
{
DataSet data = Data.DataSet;
foreach (CabinetSubject item in schedule)
{
ContentValues eventValues = new ContentValues();
eventValues.Put(CalendarContract.Events.InterfaceConsts.CalendarId, data.Calendar);
eventValues.Put(CalendarContract.Events.InterfaceConsts.Title, string.Format("{0}{1}. {2} ({3})",
item.ProfessorSchedule ? "📚 " : (data.AddGroupToTitle ? $"[{data.Group}] " : ""),
item.Order,
item.Name,
item.Type));
eventValues.Put(CalendarContract.Events.InterfaceConsts.Description, item.Opponent);
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventLocation, item.Cabinet);
eventValues.Put(CalendarContract.Events.InterfaceConsts.Availability, 0);
eventValues.Put(CalendarContract.Events.InterfaceConsts.HasAlarm, data.Reminder != -5);
// For some reason Google calendars ignore HasAlarm = false and set reminder for 30 minutes. Local calendars don't seem to have this issue
eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtstart, item.StartTime.ToUnixTime());
eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtend, item.EndTime.ToUnixTime());
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone, TimeZone.Default.ID);
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventEndTimezone, TimeZone.Default.ID);
eventValues.Put(CalendarContract.Events.InterfaceConsts.CustomAppPackage, Application.Context.PackageName);
Uri response = Application.Context.ContentResolver.Insert(CalendarContract.Events.ContentUri, eventValues);
// Settings reminder
if(data.Reminder != -5)
{
ContentValues reminderValues = new ContentValues();
reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.EventId, long.Parse(response.LastPathSegment));
reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.Minutes, data.Reminder);
Application.Context.ContentResolver.Insert(CalendarContract.Reminders.ContentUri, reminderValues);
}
}
}
public static void Clear(bool keepPrevious = true)
{
Uri contentUri = CalendarContract.Events.ContentUri;
string selector = $"({CalendarContract.Events.InterfaceConsts.CustomAppPackage} == \"{Application.Context.PackageName}\") AND (deleted != 1)";
if (keepPrevious)
selector += $" AND (dtstart > {System.DateTime.Now.ToUnixTime()})";
string[] calendarsProjection = {
CalendarContract.Events.InterfaceConsts.Id,
CalendarContract.Events.InterfaceConsts.Dtstart,
CalendarContract.Events.InterfaceConsts.CustomAppPackage,
};
// Retrieving calendars data
ICursor cursor = Application.Context.ContentResolver.Query(contentUri, calendarsProjection, selector, null, null);
while (cursor.MoveToNext())
Application.Context.ContentResolver.Delete(ContentUris.WithAppendedId(CalendarContract.Events.ContentUri, cursor.GetLong(0)), null, null);
cursor.Close();
}
}
}
-71
View File
@@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Android.Content;
using Android.Widget;
namespace GUT.Schedule
{
public static class Extensions
{
/// <summary>
/// Sets array as Spinner dropdown list content
/// </summary>
/// <typeparam name="T">Array items type</typeparam>
/// <param name="spinner">Spinner on which array will be assigned to</param>
/// <param name="context">Current activity context. In most common cases <c>this</c> will do</param>
/// <param name="array">Array of items to be displayed</param>
public static void SetList<T>(this Spinner spinner, Context context, IEnumerable<T> array)
{
ArrayAdapter adapter = new ArrayAdapter(context, Resource.Layout.support_simple_spinner_dropdown_item, array.ToList());
spinner.Adapter = adapter;
}
/// <summary>
/// Returns <see cref="DateTime"/> instance based on study week number, weekday and semester start day number
/// </summary>
/// <param name="week">Number of the study week</param>
/// <param name="weekday">Weekday</param>
/// <returns><see cref="DateTime"/> instance based on study week number, weekday and semester start day number</returns>
public static DateTime GetDateFromWeeks(int week, int weekday)
{
DateTime dt = new DateTime(DateTime.Today.Year, DateTime.Today.Month >= 8 ? 9 : 2, Data.FirstWeekDay);
dt = dt.AddDays(--week * 7);
dt = dt.AddDays(--weekday);
return dt;
}
/// <summary>
/// Converts <see cref="DateTime"/> to milliseconds count
/// </summary>
/// <remarks>In the nearest future we will be fucked because of that shit</remarks>
/// <param name="dt"><see cref="DateTime"/> which is to be converted to UNIX time</param>
/// <returns><see cref="long"/> which is represented by total milliseconds count passed since 1970</returns>
public static long ToUnixTime(this DateTime dt) =>
(long)dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
public static void SetContent(this HttpRequestMessage request, params (string key, string value)[] values)
{
if (request == null)
throw new ArgumentNullException(nameof(request));
Dictionary<string, string> body = new Dictionary<string, string>();
foreach ((string key, string value) in values)
body.Add(key, value);
request.Content = new FormUrlEncodedContent(body);
}
public static async Task<string> GetString(this HttpResponseMessage response)
{
if (response == null)
throw new ArgumentNullException(nameof(response));
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
return Encoding.GetEncoding("Windows-1251").GetString(await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false));
}
}
}
@@ -1,50 +0,0 @@
using System;
using Android.OS;
using Android.Widget;
using Android.App;
using System.Threading.Tasks;
using Android.Content;
namespace GUT.Schedule
{
/// <summary>
/// Date picker
/// </summary>
public class DatePickerFragment : Android.Support.V4.App.DialogFragment, DatePickerDialog.IOnDateSetListener
{
DateTime _date;
bool dismissed = false;
public override Dialog OnCreateDialog(Bundle savedInstanceState) =>
new DatePickerDialog(Activity, this, _date.Year, _date.Month - 1, _date.Day);
// Occures when user selected a date
public void OnDateSet(DatePicker view, int year, int month, int dayOfMonth)
{
_date = view.DateTime;
dismissed = true;
}
public override void OnCancel(IDialogInterface dialog)
{
base.OnCancel(dialog);
dismissed = true;
}
/// <summary>
/// Shows date picker and waits for user input
/// </summary>
/// <param name="manager">Fragment manager of the current activity (In most common cases it is <c>this.FragmentManager</c>)</param>
/// <param name="date">Date which is to be selected by default</param>
/// <returns><see cref="DateTime"/> picked by user</returns>
public async Task<DateTime> GetDate(Android.Support.V4.App.FragmentManager manager, DateTime date)
{
_date = date;
Show(manager, "datePicker");
while (!dismissed)
await Task.Delay(100);
return _date;
}
}
}
@@ -1,46 +0,0 @@
using System;
namespace GUT.Schedule.Models
{
public class CabinetSubject
{
public string Name { get; set; }
public string Type { get; set; }
public string Cabinet { get; set; }
public string Order { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string Opponent { get; set; }
public bool ProfessorSchedule { get; set; }
public CabinetSubject(string name, string type, string cabinet, string opponent, int year, int month, int day, string schedule, bool profSchedule)
{
Name = name;
Type = type;
Cabinet = cabinet;
Opponent = opponent;
ProfessorSchedule = profSchedule;
string[] time = schedule.Split('-');
StartTime = new DateTime(year, month, day, int.Parse(time[0].Split('.')[0]), int.Parse(time[0].Split('.')[1]), 0);
EndTime = new DateTime(year, month, day, int.Parse(time[1].Split('.')[0]), int.Parse(time[1].Split('.')[1]), 0);
Order = time[0] switch
{
"09.00" => "1",
"10.45" => "2",
"13.00" => "3",
"14.45" => "4",
"16.30" => "5",
"18.15" => "6",
"20.00" => "7",
"10.30" => "2", //Расписание для пар по физ-ре
"12.00" => "3",
"13.30" => "4",
"15.00" => "5",
"18.00" => "7",
_ => ""
};
}
}
}
-20
View File
@@ -1,20 +0,0 @@
using GUT.Schedule.Models;
using System;
using System.Collections.Generic;
namespace GUT.Schedule
{
public static class Data
{
public static List<(string Id, string Name)> Faculties { get; set; }
public static List<(string Id, string Name)> Groups { get; set; }
public static int FirstWeekDay { get; set; }
public static DateTime StartDate { get; set; } = DateTime.Today;
public static DateTime EndDate { get; set; } = DateTime.Today.AddDays(7);
/// <summary>
/// Export parameters
/// </summary>
public static DataSet DataSet { get; set; }
}
}
@@ -1,16 +0,0 @@
using System.Net.Http;
namespace GUT.Schedule.Models
{
public class DataSet
{
public string Calendar { get; set; }
public string Faculty { get; set; }
public int Course { get; set; }
public string Group { get; set; }
public int Reminder { get; set; }
public bool AddGroupToTitle { get; set; }
public HttpClient HttpClient { get; set; }
public bool? IsProfessor { get; set; }
}
}
@@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
namespace GUT.Schedule.Models
{
public class Subject
{
public string Name { get; set; }
public string Type { get; set; }
public string Professor { get; set; }
public string[] Cabinets { get; set; }
public string Order { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string Group { get; set; }
public static List<Subject> GetSubject(string name, string type, string professor, string place, int order, string[] weeks, int weekday, string group)
{
List<Subject> subjects = new List<Subject>();
string[] cabinets = place.Replace("ауд.: ", "").Replace("; Б22", "").Split(';');
string pair = order < 10 ? order.ToString() : $"Ф{order - 81}";
foreach (string week in weeks)
subjects.Add(new Subject(name, type, professor, cabinets, pair, int.Parse(week), weekday, group));
return subjects;
}
public Subject(string name, string type, string prof, string[] cabs, string order, int week, int weekday, string group)
{
Name = name;
Type = type;
Professor = prof;
Cabinets = cabs;
Order = order;
Group = group;
StartTime = Extensions.GetDateFromWeeks(week, weekday);
StartTime = StartTime.Add(TimeSpan.Parse(order switch
{
"1" => "9:00",
"2" => "10:45",
"3" => "13:00",
"4" => "14:45",
"5" => "16:30",
"6" => "18:15",
"7" => "20:00",
"Ф1" => "9:00", //Расписание для пар по физ-ре
"Ф2" => "10:30",
"Ф3" => "12:00",
"Ф4" => "13:30",
"Ф5" => "15:00",
"Ф6" => "16:30",
"Ф7" => "18:00",
_ => "9:00"
}));
EndTime = StartTime + TimeSpan.FromMinutes(order.Contains("Ф") ? 90 : 95);
}
}
}
-178
View File
@@ -1,178 +0,0 @@
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
using AngleSharp.Html.Parser;
using GUT.Schedule.Models;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace GUT.Schedule
{
public static class Parser
{
public static async Task<List<Subject>> LoadSchedule()
{
List<Subject> schedule = new List<Subject>();
using HttpClient client = new HttpClient();
Dictionary<string, string> requestBody = new Dictionary<string, string>
{
{ "group_el", "0" },
{ "kurs", Data.DataSet.Course.ToString() },
{ "type_z", "1" },
{ "faculty", Data.DataSet.Faculty },
{ "group", Data.DataSet.Group },
{ "ok", "Показать" },
{ "schet", GetCurrentSemester() }
};
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://cabinet.sut.ru/raspisanie_all_new")
{
Content = new FormUrlEncodedContent(requestBody)
};
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpResponseMessage response = await client.SendAsync(request);
IHtmlDocument doc = new HtmlParser().ParseDocument(await response.Content.ReadAsStringAsync());
string groupName = Data.Groups.First(i => i.Id == Data.DataSet.Group).Name;
IHtmlCollection<IElement> pairs = doc.QuerySelectorAll(".pair");
foreach (IElement item in pairs)
{
string name, type, professor, place;
int order, weekday;
string[] weeks;
name = item.QuerySelector(".subect strong")?.TextContent ?? "Неизвестный предмет (см. Расписание)";
type = item.QuerySelector(".type").TextContent.Replace("(", "").Replace(")", "");
professor = item.QuerySelector(".teacher")?.GetAttribute("title").Replace(";", "") ?? "";
place = item.QuerySelector(".aud")?.TextContent ?? "СПбГУТ";
order = int.Parse(item.GetAttribute("pair")) - 1;
weeks = item.QuerySelector(".weeks").TextContent.Replace("(", "").Replace("н)", "").Split(", ");
weekday = int.Parse(item.GetAttribute("weekday"));
schedule.AddRange(Subject.GetSubject(name, type, professor, place, order, weeks, weekday, groupName));
}
return schedule;
}
public static async Task LoadFaculties()
{
Data.Faculties = new List<(string, string)>();
using HttpClient client = new HttpClient();
Dictionary<string, string> requestBody = new Dictionary<string, string>
{
{ "choice", "1" },
{ "kurs", "0" },
{ "type_z", "1" },
{ "schet", GetCurrentSemester() }
};
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://cabinet.sut.ru/raspisanie_all_new.php")
{
Content = new FormUrlEncodedContent(requestBody)
};
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpResponseMessage response = await client.SendAsync(request);
string responseBody = await response.Content.ReadAsStringAsync();
if (string.IsNullOrWhiteSpace(responseBody))
throw new NullReferenceException("Расписание на текущий семестр еще не объявлено");
foreach (string s in responseBody.Split(';'))
try { Data.Faculties.Add((s.Split(',')[0], s.Split(',')[1])); }
catch { }
}
public static async Task LoadGroups(string facultyId, int course)
{
using HttpClient client = new HttpClient();
Dictionary<string, string> requestBody = new Dictionary<string, string>
{
{ "choice", "1" },
{ "kurs", course.ToString() },
{ "type_z", "1" },
{ "faculty", facultyId },
{ "schet", GetCurrentSemester() }
};
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://cabinet.sut.ru/raspisanie_all_new.php")
{
Content = new FormUrlEncodedContent(requestBody)
};
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpResponseMessage response = await client.SendAsync(request);
string responseBody = await response.Content.ReadAsStringAsync();
Data.Groups = new List<(string, string)>();
foreach (string s in responseBody.Split(';'))
try { Data.Groups.Add((s.Split(',')[0], s.Split(',')[1])); }
catch { }
}
static string GetCurrentSemester()
{
DateTime now = DateTime.Today;
if (now.Month > 8)
return $"205.{now.Year - 2000}{now.Year - 1999}/1";
else
return $"205.{now.Year - 2001}{now.Year - 2000}/2";
}
public static async Task<List<CabinetSubject>> GetCabinetSchedule(HttpClient client, DateTime date, bool checkProfSchedule)
{
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"https://cabs.itut.ru/cabinet/project/cabinet/forms/{(checkProfSchedule ? "pr_" : "")}raspisanie_kalendar.php");
request.SetContent(
("month", date.Month.ToString()),
("year", date.Year.ToString()),
("type_z", "0"));
HttpResponseMessage response = await client.SendAsync(request).ConfigureAwait(false);
string responseContent = await response.GetString().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
throw new HttpRequestException(responseContent);
IHtmlDocument doc = new HtmlParser().ParseDocument(responseContent);
List<CabinetSubject> schedule = new List<CabinetSubject>();
if(!checkProfSchedule)
Data.DataSet.Group = doc.QuerySelector(".style_gr b").TextContent;
foreach (var i in doc.QuerySelectorAll("td").Where(i => i.GetAttribute("style") == "text-align: center; vertical-align: top"))
for (int k = 0; k < i.QuerySelectorAll("i").Length; k++)
{
CabinetSubject item = new CabinetSubject(
name: i.QuerySelectorAll("b")[k * 2 + 1].TextContent,
type: i.QuerySelectorAll("i")[k].TextContent,
cabinet: i.QuerySelectorAll("small")[k].NextSibling.TextContent.Replace("; Б22", ""),
opponent: i.QuerySelectorAll("i")[k].NextSibling.NextSibling.NodeType == NodeType.Text ?
i.QuerySelectorAll("i")[k].NextSibling.NextSibling.TextContent : "",
year: date.Year,
month: date.Month,
day: int.Parse(i.ChildNodes[0].TextContent),
schedule: i.QuerySelectorAll("b")[k * 2 + 2].TextContent,
checkProfSchedule);
schedule.Add(item);
}
// Merge duplicating entries
schedule.OrderByDescending(i => i.StartTime);
for(int k = 1; k < schedule.Count; k++)
if(schedule[k - 1].StartTime == schedule[k].StartTime &&
schedule[k - 1].Name == schedule[k].Name &&
schedule[k - 1].Type == schedule[k].Type)
{
schedule[k - 1].Opponent += "\n" + schedule[k].Opponent;
schedule[k - 1].Cabinet += "; " + schedule[k].Cabinet;
schedule.RemoveAt(k--);
}
return schedule;
}
}
}
@@ -0,0 +1,86 @@
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Support.V4.Text;
using Android.Support.V7.App;
using Android.Text.Method;
using Android.Widget;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
namespace GUTSchedule.Droid.Activities
{
[Activity(Label = "@string/aboutTitle")]
public class AboutActivity : AppCompatActivity
{
protected override async void OnCreate(Bundle savedInstanceState)
{
(string name, string handle, string link)[] contacts = new (string, string, string)[]
{
(Resources.GetText(Resource.String.websiteContact), "https://xfox111.net", "https://xfox111.net"),
(Resources.GetText(Resource.String.twitterContact), "@xfox111", "https://twitter.com/xfox111"),
(Resources.GetText(Resource.String.vkontakteContact), "@xfox.mike", "https://vk.com/xfox.mike"),
("LinkedIn", "@xfox", "https://linkedin.com/in/xfox"),
("GitHub", "@xfox111", "https://github.com/xfox111"),
};
(string name, string link)[] links = new (string, string)[]
{
(Resources.GetText(Resource.String.privacyPolicyLink), "https://xfox111.net/Projects/GUTSchedule/PrivacyPolicy.txt"),
("General Public License v3", "https://www.gnu.org/licenses/gpl-3.0"),
(Resources.GetText(Resource.String.repositoryLink), "https://github.com/xfox111/gutschedule"),
(Resources.GetText(Resource.String.notsLink), "http://tios.spbgut.ru/index.php"),
(Resources.GetText(Resource.String.sutLink), "https://sut.ru"),
};
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.About);
PackageInfo version = PackageManager.GetPackageInfo(PackageName, PackageInfoFlags.MatchAll);
FindViewById<TextView>(Resource.Id.version).Text = $"v{version.VersionName} (ci-id #{version.VersionCode})";
FindViewById<Button>(Resource.Id.feedback).Click += (s, e) =>
StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("mailto:feedback@xfox111.net")));
FindViewById<TextView>(Resource.Id.contacts).SetText(
HtmlCompat.FromHtml(string.Join("<br />", contacts.Select(i => $"<span>{i.name}:</span> <a href=\"{i.link}\">{i.handle}</a>")), HtmlCompat.FromHtmlModeLegacy),
TextView.BufferType.Normal);
FindViewById<TextView>(Resource.Id.contacts).MovementMethod = LinkMovementMethod.Instance;
FindViewById<TextView>(Resource.Id.links).SetText(
HtmlCompat.FromHtml(string.Join("<br />", links.Select(i => $"<a href=\"{i.link}\">{i.name}</a>")), HtmlCompat.FromHtmlModeLegacy),
TextView.BufferType.Normal);
FindViewById<TextView>(Resource.Id.links).MovementMethod = LinkMovementMethod.Instance;
List<string> contributors = new List<string>();
try
{
using HttpClient client = new HttpClient();
using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/repos/xfox111/gutschedule/contributors");
request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0");
HttpResponseMessage response = await client.SendAsync(request);
string resposeContent = await response.Content.ReadAsStringAsync();
dynamic parsedResponse = JsonConvert.DeserializeObject(resposeContent);
foreach (var i in parsedResponse)
if (i.type == "User" && ((string)i.login).ToLower() != "xfox111")
contributors.Add((string)i.login);
}
finally
{
if (contributors.Count > 0)
{
FindViewById<TextView>(Resource.Id.contributors).SetText(
HtmlCompat.FromHtml(string.Join(", ", contributors.Select(i => $"<a href=\"https://github.com/{i}\">@{i}</a>")), HtmlCompat.FromHtmlModeLegacy),
TextView.BufferType.Normal);
FindViewById<TextView>(Resource.Id.contributors).MovementMethod = LinkMovementMethod.Instance;
FindViewById<TextView>(Resource.Id.contributorsTitle).Visibility = Android.Views.ViewStates.Visible;
FindViewById<TextView>(Resource.Id.contributors).Visibility = Android.Views.ViewStates.Visible;
}
}
}
}
}
@@ -0,0 +1,72 @@
using Android.App;
using Android.OS;
using Android.Widget;
using GUTSchedule.Models;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace GUTSchedule.Droid.Activities
{
/// <summary>
/// Shows status of schedule export process
/// </summary>
[Activity(Theme = "@style/AppTheme.Light.SplashScreen")]
public class ExportActivity : Activity
{
TextView status;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Export);
status = FindViewById<TextView>(Resource.Id.status);
Export();
}
private async void Export()
{
try
{
status.Text = Resources.GetText(Resource.String.loadingStatus);
List<Occupation> schedule = await Parser.GetSchedule(MainActivity.ExportParameters);
status.Text = Resources.GetText(Resource.String.calendarExportStatus);
Calendar.Export(schedule);
status.Text = Resources.GetText(Resource.String.doneStatus);
await Task.Delay(1000);
}
catch (HttpRequestException e)
{
Android.Support.V7.App.AlertDialog.Builder builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(Resources.GetText(Resource.String.connectionFailMessage))
.SetTitle(e.Message)
.SetPositiveButton("ОК", (s, e) => base.OnBackPressed())
.SetNegativeButton(Resources.GetText(Resource.String.repeat), (s, e) => Export());
Android.Support.V7.App.AlertDialog dialog = builder.Create();
dialog.Show();
return;
}
catch (Exception e)
{
Android.Support.V7.App.AlertDialog.Builder builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(e.Message)
.SetTitle(e.GetType().ToString())
.SetPositiveButton("ОК", (s, e) => base.OnBackPressed());
Android.Support.V7.App.AlertDialog dialog = builder.Create();
dialog.Show();
return;
}
base.OnBackPressed(); // Navigates back to main activity (always because I don't allow backward navigation)
}
public override void OnBackPressed() { } // Disables back button
}
}
@@ -0,0 +1,335 @@
using System;
using System.Linq;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Preferences;
using Android.Support.V7.App;
using Android.Text.Method;
using Android.Views;
using Android.Widget;
using GUTSchedule.Models;
using GUTSchedule.Droid.Fragments;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace GUTSchedule.Droid.Activities
{
[Activity]
public class MainActivity : AppCompatActivity
{
public static ExportParameters ExportParameters { get; set; }
public static List<(string id, string name)> Faculties { get; set; }
public static List<(string id, string name)> Groups { get; set; }
public static bool AddGroupToTitle { get; set; }
public static int SelectedCalendarIndex { get; set; }
public static int Reminder { get; set; }
DateTime startDate = DateTime.Today;
DateTime endDate = DateTime.Today.AddDays(7);
Button start, end, export;
Button forDay, forWeek, forMonth, forSemester;
Spinner faculty, course, group, reminder, calendar;
CheckBox groupTitle, authorize;
TextView error;
LinearLayout studentParams, profParams;
EditText email, password;
ISharedPreferences prefs;
protected override async void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
PackageInfo version = PackageManager.GetPackageInfo(PackageName, PackageInfoFlags.MatchAll);
FindViewById<TextView>(Resource.Id.version).Text = $"v{version.VersionName} (ci-id #{version.VersionCode})";
prefs = PreferenceManager.GetDefaultSharedPreferences(this);
AssignVariables();
faculty.SetList(this, Faculties.Select(i => i.name));
int s = Faculties.FindIndex(i => i.id == prefs.GetString("Faculty", "-123"));
faculty.SetSelection(s == -1 ? 0 : s);
course.SetList(this, "1234".ToCharArray());
course.SetSelection(prefs.GetInt("Course", 0)); // IDK why but this shit triggers events anyway (even if they are set in the next line. It seem to be that there's some asynchronous shit somewhere there)
// P.S. Fuck Android
await Task.Delay(100);
UpdateGroupsList();
AddEvents();
// Settings spinners' dropdown lists content
reminder.SetList(this, new[]
{
Resources.GetText(Resource.String.noReminderOption),
Resources.GetText(Resource.String.inTimeReminderOption),
Resources.GetText(Resource.String.fiveMinuteReminderOption),
Resources.GetText(Resource.String.tenMinuteReminderOption)
});
reminder.SetSelection(prefs.GetInt("Reminder", 0));
calendar.SetList(this, Calendar.Calendars.Select(i => i.Name));
s = Calendar.Calendars.FindIndex(i => i.Id == prefs.GetString("Calendar", "-123"));
calendar.SetSelection(s == -1 ? 0 : s);
end.Text = endDate.ToShortDateString();
start.Text = startDate.ToShortDateString();
groupTitle.Checked = prefs.GetBoolean("AddGroupToHeader", false);
authorize.Checked = prefs.GetBoolean("Authorize", true);
email.Text = prefs.GetString("email", "");
password.Text = prefs.GetString("password", "");
}
private void Export_Click(object sender, EventArgs e)
{
error.Visibility = ViewStates.Gone;
if (startDate > endDate)
{
error.Text = Resources.GetText(Resource.String.invalidDateRangeError);
error.Visibility = ViewStates.Visible;
return;
}
if (authorize.Checked)
{
if (string.IsNullOrWhiteSpace(email.Text) || string.IsNullOrWhiteSpace(password.Text))
{
error.Text = Resources.GetText(Resource.String.invalidAuthorizationError);
error.Visibility = ViewStates.Visible;
return;
}
ExportParameters = new CabinetExportParameters
{
Email = email.Text,
Password = password.Text,
EndDate = endDate,
StartDate = startDate
};
// Если ты это читаешь и у тебя возникли вопросы по типу "А какого хуя творится в коде ниже?!", то во-первых:
// According to this SO thread: https://stackoverflow.com/questions/1925486/android-storing-username-and-password
// I consider Preferences as safe enough method for storing credentials
// А во-вторых, даже такой казалось бы небезопасный метод хранения учетных данных в сто раз надежнее того дерьма,
// что творится на серверах Бонча (я не шучу, там все ОЧЕНЬ плохо)
// Ну и в-третьих: Андроид - это пиздец и настоящий ад разработчика. И если бы была моя воля, я бы под него никогда не писал #FuckAndroid
// З.Ы. Помнишь про второй пункт? Так вот, если ты используешь такой же пароль как в ЛК где-то еще, настоятельно рекомендую его поменять
PreferenceManager.GetDefaultSharedPreferences(this).Edit().PutString("email", email.Text).Apply();
PreferenceManager.GetDefaultSharedPreferences(this).Edit().PutString("password", password.Text).Apply();
}
else
{
if (Groups.Count < 1)
{
error.Text = Resources.GetText(Resource.String.groupSelectionError);
error.Visibility = ViewStates.Visible;
return;
}
ExportParameters = new DefaultExportParameters
{
EndDate = endDate,
StartDate = startDate,
Course = (course.SelectedItemPosition + 1).ToString(),
FacultyId = Faculties[faculty.SelectedItemPosition].id,
GroupId = Groups[group.SelectedItemPosition].id,
};
}
AddGroupToTitle = groupTitle.Checked;
SelectedCalendarIndex = calendar.SelectedItemPosition;
Reminder = (reminder.SelectedItemPosition - 1) * 5;
StartActivity(new Intent(this, typeof(ExportActivity)));
}
private async void End_Click(object sender, EventArgs e)
{
endDate = await new DatePickerFragment().GetDate(SupportFragmentManager, endDate);
end.Text = endDate.ToShortDateString();
}
private async void Start_Click(object sender, EventArgs e)
{
startDate = await new DatePickerFragment().GetDate(SupportFragmentManager, startDate);
start.Text = startDate.ToShortDateString();
}
private async void UpdateGroupsList()
{
if (course.SelectedItem == null)
return;
Groups = await Parser.GetGroups(Faculties[faculty.SelectedItemPosition].id, (course.SelectedItemPosition + 1).ToString());
group.SetList(this, Groups.Select(i => i.name));
int s = Groups?.FindIndex(i => i.id == prefs.GetString("Group", "-123")) ?? 0;
group.SetSelection(s == -1 ? 0 : s);
}
private void SetDate(int days)
{
endDate = startDate.AddDays(days);
end.Text = endDate.ToShortDateString();
}
#region Init stuff
private void AssignVariables()
{
start = FindViewById<Button>(Resource.Id.start);
end = FindViewById<Button>(Resource.Id.end);
export = FindViewById<Button>(Resource.Id.export);
forDay = FindViewById<Button>(Resource.Id.forDay);
forWeek = FindViewById<Button>(Resource.Id.forWeek);
forMonth = FindViewById<Button>(Resource.Id.forMonth);
forSemester = FindViewById<Button>(Resource.Id.forSemester);
faculty = FindViewById<Spinner>(Resource.Id.faculty);
course = FindViewById<Spinner>(Resource.Id.course);
group = FindViewById<Spinner>(Resource.Id.group);
reminder = FindViewById<Spinner>(Resource.Id.reminder);
calendar = FindViewById<Spinner>(Resource.Id.calendar);
error = FindViewById<TextView>(Resource.Id.error);
groupTitle = FindViewById<CheckBox>(Resource.Id.groupTitle);
authorize = FindViewById<CheckBox>(Resource.Id.authorization);
studentParams = FindViewById<LinearLayout>(Resource.Id.studentParams);
profParams = FindViewById<LinearLayout>(Resource.Id.professorParams);
email = FindViewById<EditText>(Resource.Id.email);
password = FindViewById<EditText>(Resource.Id.password);
}
private void AddEvents()
{
faculty.ItemSelected += (s, e) =>
{
prefs.Edit().PutString("Faculty", Faculties[e.Position].id).Apply();
UpdateGroupsList();
};
course.ItemSelected += (s, e) =>
{
prefs.Edit().PutInt("Course", e.Position).Apply();
UpdateGroupsList();
};
authorize.CheckedChange += (s, e) =>
{
prefs.Edit().PutBoolean("Authorize", e.IsChecked).Apply();
if (e.IsChecked)
{
studentParams.Visibility = ViewStates.Gone;
profParams.Visibility = ViewStates.Visible;
}
else
{
studentParams.Visibility = ViewStates.Visible;
profParams.Visibility = ViewStates.Gone;
}
};
calendar.ItemSelected += (s, e) =>
prefs.Edit().PutString("Calendar", Calendar.Calendars[e.Position].Id).Apply();
reminder.ItemSelected += (s, e) =>
prefs.Edit().PutInt("Reminder", e.Position).Apply();
group.ItemSelected += (s, e) =>
prefs.Edit().PutString("Group", Groups[e.Position].id).Apply();
groupTitle.Click += (s, e) =>
prefs.Edit().PutBoolean("AddGroupToHeader", groupTitle.Checked).Apply();
forDay.Click += (s, e) => SetDate(0);
forWeek.Click += (s, e) => SetDate(6);
forMonth.Click += (s, e) => SetDate(30);
forSemester.Click += (s, e) =>
{
if (DateTime.Today.Month == 1)
endDate = new DateTime(DateTime.Today.Year, 1, 31);
else if (DateTime.Today.Month > 8)
endDate = new DateTime(DateTime.Today.Year + 1, 1, 31);
else
endDate = new DateTime(DateTime.Today.Year, 8, 31);
end.Text = endDate.ToShortDateString();
};
start.Click += Start_Click;
end.Click += End_Click;
export.Click += Export_Click;
}
#endregion
#region Menu stuff
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.MainContextMenu, menu);
return true;
}
public void Clear(bool keepPrevious = true)
{
try
{
Toast.MakeText(ApplicationContext, Resources.GetText(Resource.String.clearingStatus), ToastLength.Short).Show();
Calendar.Clear(keepPrevious);
Toast.MakeText(ApplicationContext, Resources.GetText(Resource.String.doneStatus), ToastLength.Short).Show();
}
catch (Exception e)
{
Android.Support.V7.App.AlertDialog.Builder builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(e.Message)
.SetTitle(e.GetType().ToString())
.SetPositiveButton("ОК", (IDialogInterfaceOnClickListener)null);
Android.Support.V7.App.AlertDialog dialog = builder.Create();
dialog.Show();
}
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
Android.Support.V7.App.AlertDialog.Builder builder;
Android.Support.V7.App.AlertDialog dialog;
switch (item.ItemId)
{
case Resource.Id.about:
StartActivity(new Intent(this, typeof(AboutActivity)));
return true;
case Resource.Id.email:
StartActivity(new Intent(Intent.ActionView, Android.Net.Uri.Parse("mailto:feedback@xfox111.net")));
return true;
case Resource.Id.clear:
builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(Resources.GetText(Resource.String.clearScheduleMessage))
.SetTitle(Resources.GetText(Resource.String.clearScheduleTitle))
.SetPositiveButton(Resources.GetText(Resource.String.clearUpcomingOption), (s, e) => Clear())
.SetNegativeButton(Resources.GetText(Resource.String.clearAllOption), (s, e) => Clear(false))
.SetNeutralButton(Resources.GetText(Resource.String.cancelOption), (IDialogInterfaceOnClickListener)null);
dialog = builder.Create();
dialog.Show();
// Making links clickable
dialog.FindViewById<TextView>(Android.Resource.Id.Message).MovementMethod = LinkMovementMethod.Instance;
return true;
}
return base.OnOptionsItemSelected(item);
}
#endregion
public override void OnBackPressed() =>
FinishAffinity(); // Close application
}
}
@@ -0,0 +1,110 @@
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using Android.Support.V4.App;
using Android.Support.V4.Content;
using Android.Support.V7.App;
using Android.Widget;
using GUTSchedule;
using GUTSchedule.Droid;
using GUTSchedule.Droid.Activities;
using System;
using System.Linq;
using System.Net.Http;
namespace GUT.Schedule.Droid.Activities
{
/// <summary>
/// Splash screen activity. Loads init data
/// </summary>
[Activity(MainLauncher = true, Theme = "@style/AppTheme.Light.SplashScreen")]
public class StartActivity : AppCompatActivity
{
TextView status;
protected override void OnCreate(Bundle savedInstanceState)
{
SetContentView(Resource.Layout.SplashScreen);
base.OnCreate(savedInstanceState);
status = FindViewById<TextView>(Resource.Id.status);
PackageInfo version = PackageManager.GetPackageInfo(PackageName, PackageInfoFlags.MatchAll);
FindViewById<TextView>(Resource.Id.version).Text = $"v{version.VersionName} (ci-id #{version.VersionCode})";
status.Text = Resources.GetText(Resource.String.permissionsCheckStatus);
if (ContextCompat.CheckSelfPermission(this, Android.Manifest.Permission.WriteCalendar) != Permission.Granted)
{
if (ActivityCompat.ShouldShowRequestPermissionRationale(this, Android.Manifest.Permission.WriteCalendar))
ShowDialog(Resources.GetText(Resource.String.calendarAccessTitle), Resources.GetText(Resource.String.calendarAccessRationale), RequestPermissions);
else
RequestPermissions();
}
else
Proceed();
}
private async void Proceed()
{
try
{
status.Text = Resources.GetText(Resource.String.calendarLoadingStatus);
Calendar.LoadCalendars();
if (Calendar.Calendars.Count == 0)
{
ShowDialog(Resources.GetText(Resource.String.createCalendarTitle), Resources.GetText(Resource.String.createCalendarMessage));
return;
}
status.Text = Resources.GetText(Resource.String.facultiesLoadingStatus);
MainActivity.Faculties = await Parser.GetFaculties();
}
catch (HttpRequestException e)
{
ShowDialog(e.Message, Resources.GetText(Resource.String.connectionFailMessage), Proceed, FinishAndRemoveTask, Resources.GetText(Resource.String.repeat), Resources.GetText(Resource.String.quit));
return;
}
catch (Exception e)
{
ShowDialog(e.GetType().ToString(), e.Message, FinishAndRemoveTask);
return;
}
StartActivity(new Intent(this, typeof(MainActivity)));
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.All(i => i == Permission.Granted))
Proceed();
else
ShowDialog(Resources.GetText(Resource.String.calendarAccessTitle), Resources.GetText(Resource.String.calendarAccessRationale), RequestPermissions);
}
private void RequestPermissions() =>
ActivityCompat.RequestPermissions(this, new[]
{
Android.Manifest.Permission.ReadCalendar,
Android.Manifest.Permission.WriteCalendar,
Android.Manifest.Permission.Internet
}, 0);
private void ShowDialog(string title, string content, Action posAction = null, Action negAction = null, string posActionLabel = null, string negActionLabel = null)
{
Android.Support.V7.App.AlertDialog.Builder builder = new Android.Support.V7.App.AlertDialog.Builder(this);
builder.SetMessage(content)
.SetTitle(title).SetPositiveButton(posActionLabel ?? "OK", (s, e) => posAction?.Invoke());
if (negAction != null)
builder.SetNegativeButton(negActionLabel ?? Resources.GetText(Resource.String.close), (s, e) => negAction.Invoke());
Android.Support.V7.App.AlertDialog dialog = builder.Create();
dialog.Show();
}
public override void OnBackPressed() { } // Disables back button
}
}
+108
View File
@@ -0,0 +1,108 @@
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Database;
using Android.Net;
using Android.Provider;
using GUTSchedule.Droid.Activities;
using GUTSchedule.Models;
using Java.Util;
namespace GUTSchedule.Droid
{
public static class Calendar
{
/// <summary>
/// List of all existing Google calendars on the device
/// </summary>
public static List<(string Id, string Name)> Calendars { get; private set; } = new List<(string Id, string Name)>();
/// <summary>
/// Retrieves all Google Accounts' calendars existing on the device and puts them to <see cref="Calendars"/>
/// </summary>
public static void LoadCalendars()
{
Calendars = new List<(string, string)>(); // Resetting current calendars list
// Building calendar data retrieval projections
Uri calendarsUri = CalendarContract.Calendars.ContentUri;
string[] calendarsProjection = {
CalendarContract.Calendars.InterfaceConsts.Id,
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
CalendarContract.Calendars.InterfaceConsts.AccountName
};
// Retrieving calendars data
ICursor cursor = Application.Context.ContentResolver.Query(calendarsUri, calendarsProjection, null, null, null);
while (cursor.MoveToNext())
Calendars.Add((cursor.GetString(0), $"{cursor.GetString(1)} ({cursor.GetString(2)})"));
cursor.Close();
}
public static void Export(IEnumerable<Occupation> schedule)
{
foreach (Occupation item in schedule)
{
ContentValues eventValues = new ContentValues();
eventValues.Put(CalendarContract.Events.InterfaceConsts.CalendarId, Calendars[MainActivity.SelectedCalendarIndex].Id);
eventValues.Put(CalendarContract.Events.InterfaceConsts.Title, string.Format("{0}.{1} {2} ({3})",
item.Order,
MainActivity.AddGroupToTitle && !string.IsNullOrWhiteSpace(item.Group) ? $" [{item.Group}]" : "",
item.Name,
item.Type));
eventValues.Put(CalendarContract.Events.InterfaceConsts.Description, item.Opponent);
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventLocation, item.Cabinet);
eventValues.Put(CalendarContract.Events.InterfaceConsts.Availability, 0);
eventValues.Put(CalendarContract.Events.InterfaceConsts.HasAlarm, MainActivity.Reminder != -5);
// For some reason Google calendars ignore HasAlarm = false and set reminder for 30 minutes. Local calendars don't seem to have this issue
eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtstart, item.StartTime.ToUnixTime());
eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtend, item.EndTime.ToUnixTime());
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone, TimeZone.Default.ID);
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventEndTimezone, TimeZone.Default.ID);
eventValues.Put(CalendarContract.Events.InterfaceConsts.CustomAppPackage, Application.Context.PackageName);
Uri response = Application.Context.ContentResolver.Insert(CalendarContract.Events.ContentUri, eventValues);
// Settings reminder
if (MainActivity.Reminder != -5)
{
ContentValues reminderValues = new ContentValues();
reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.EventId, long.Parse(response.LastPathSegment));
reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.Minutes, MainActivity.Reminder);
Application.Context.ContentResolver.Insert(CalendarContract.Reminders.ContentUri, reminderValues);
}
}
}
public static void Clear(bool keepPrevious = true)
{
Uri contentUri = CalendarContract.Events.ContentUri;
string selector = $"({CalendarContract.Events.InterfaceConsts.CustomAppPackage} == \"{Application.Context.PackageName}\") AND (deleted != 1)";
if (keepPrevious)
selector += $" AND (dtstart > {System.DateTime.Now.ToUnixTime()})";
string[] calendarsProjection = {
CalendarContract.Events.InterfaceConsts.Id,
CalendarContract.Events.InterfaceConsts.Dtstart,
CalendarContract.Events.InterfaceConsts.CustomAppPackage,
};
// Retrieving calendars data
ICursor cursor = Application.Context.ContentResolver.Query(contentUri, calendarsProjection, selector, null, null);
while (cursor.MoveToNext())
Application.Context.ContentResolver.Delete(ContentUris.WithAppendedId(CalendarContract.Events.ContentUri, cursor.GetLong(0)), null, null);
cursor.Close();
}
}
}
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Android.Content;
using Android.Widget;
namespace GUTSchedule.Droid
{
public static class Extensions
{
/// <summary>
/// Sets array as Spinner dropdown list content
/// </summary>
/// <typeparam name="T">Array items type</typeparam>
/// <param name="spinner">Spinner on which array will be assigned to</param>
/// <param name="context">Current activity context. In most common cases <c>this</c> will do</param>
/// <param name="array">Array of items to be displayed</param>
public static void SetList<T>(this Spinner spinner, Context context, IEnumerable<T> array)
{
ArrayAdapter adapter = new ArrayAdapter(context, Resource.Layout.support_simple_spinner_dropdown_item, array.ToList());
spinner.Adapter = adapter;
}
/// <summary>
/// Converts <see cref="DateTime"/> to milliseconds count
/// </summary>
/// <remarks>In the nearest future we will be fucked because of that shit</remarks>
/// <param name="dt"><see cref="DateTime"/> which is to be converted to UNIX time</param>
/// <returns><see cref="long"/> which is represented by total milliseconds count passed since 1970</returns>
public static long ToUnixTime(this DateTime dt) =>
(long)dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
}
}
@@ -0,0 +1,50 @@
using System;
using Android.OS;
using Android.Widget;
using Android.App;
using System.Threading.Tasks;
using Android.Content;
namespace GUTSchedule.Droid.Fragments
{
/// <summary>
/// Date picker
/// </summary>
public class DatePickerFragment : Android.Support.V4.App.DialogFragment, DatePickerDialog.IOnDateSetListener
{
DateTime _date;
bool dismissed = false;
public override Dialog OnCreateDialog(Bundle savedInstanceState) =>
new DatePickerDialog(Activity, this, _date.Year, _date.Month - 1, _date.Day);
// Occures when user selected a date
public void OnDateSet(DatePicker view, int year, int month, int dayOfMonth)
{
_date = view.DateTime;
dismissed = true;
}
public override void OnCancel(IDialogInterface dialog)
{
base.OnCancel(dialog);
dismissed = true;
}
/// <summary>
/// Shows date picker and waits for user input
/// </summary>
/// <param name="manager">Fragment manager of the current activity (In most common cases it is <c>this.FragmentManager</c>)</param>
/// <param name="date">Date which is to be selected by default</param>
/// <returns><see cref="DateTime"/> picked by user</returns>
public async Task<DateTime> GetDate(Android.Support.V4.App.FragmentManager manager, DateTime date)
{
_date = date;
Show(manager, "datePicker");
while (!dismissed)
await Task.Delay(100);
return _date;
}
}
}
@@ -10,8 +10,8 @@
<TemplateGuid>{84dd83c5-0fe3-4294-9419-09e7c8ba324f}</TemplateGuid> <TemplateGuid>{84dd83c5-0fe3-4294-9419-09e7c8ba324f}</TemplateGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>GUT.Schedule</RootNamespace> <RootNamespace>GUTSchedule.Droid</RootNamespace>
<AssemblyName>GUT.Schedule</AssemblyName> <AssemblyName>GUTSchedule.Droid</AssemblyName>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<AndroidApplication>True</AndroidApplication> <AndroidApplication>True</AndroidApplication>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile> <AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
@@ -93,18 +93,13 @@
<ItemGroup> <ItemGroup>
<Compile Include="Activities\AboutActivity.cs" /> <Compile Include="Activities\AboutActivity.cs" />
<Compile Include="Calendar.cs" /> <Compile Include="Calendar.cs" />
<Compile Include="Models\Data.cs" />
<Compile Include="Fragments\DatePickerFragment.cs" /> <Compile Include="Fragments\DatePickerFragment.cs" />
<Compile Include="Activities\ExportActivity.cs" /> <Compile Include="Activities\ExportActivity.cs" />
<Compile Include="Extensions.cs" /> <Compile Include="Extensions.cs" />
<Compile Include="Activities\MainActivity.cs" /> <Compile Include="Activities\MainActivity.cs" />
<Compile Include="Models\DataSet.cs" />
<Compile Include="Models\CabinetSubject.cs" />
<Compile Include="Parser.cs" />
<Compile Include="Resources\Resource.designer.cs" /> <Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Activities\StartActivity.cs" /> <Compile Include="Activities\StartActivity.cs" />
<Compile Include="Models\Subject.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Properties\AndroidManifest.xml" /> <None Include="Properties\AndroidManifest.xml" />
@@ -133,18 +128,12 @@
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" /> <AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AngleSharp">
<Version>0.13.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.CSharp"> <PackageReference Include="Microsoft.CSharp">
<Version>4.7.0</Version> <Version>4.7.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Newtonsoft.Json"> <PackageReference Include="Newtonsoft.Json">
<Version>12.0.3</Version> <Version>12.0.3</Version>
</PackageReference> </PackageReference>
<PackageReference Include="System.Net.Http">
<Version>4.3.4</Version>
</PackageReference>
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.3" /> <PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.3" /> <PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.3" /> <PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.3" />
@@ -174,15 +163,18 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</AndroidResource> </AndroidResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Assets\" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\values\strings.xml" /> <AndroidResource Include="Resources\values\strings.xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="Resources\values-ru\strings.xml" /> <AndroidResource Include="Resources\values-ru\strings.xml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GUTSchedule\GUTSchedule.csproj">
<Project>{a6f6de35-0eb4-4d11-9ff9-f4601595b639}</Project>
<Name>GUTSchedule</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" /> <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. <!-- 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. Other similar extension points exist, see Microsoft.Common.targets.
@@ -9,9 +9,9 @@
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
[assembly: global::Android.Runtime.ResourceDesignerAttribute("GUT.Schedule.Resource", IsApplication=true)] [assembly: global::Android.Runtime.ResourceDesignerAttribute("GUTSchedule.Droid.Resource", IsApplication=true)]
namespace GUT.Schedule namespace GUTSchedule.Droid
{ {
@@ -26,188 +26,188 @@ namespace GUT.Schedule
public static void UpdateIdValues() public static void UpdateIdValues()
{ {
global::Xamarin.Essentials.Resource.Attribute.alpha = global::GUT.Schedule.Resource.Attribute.alpha; global::Xamarin.Essentials.Resource.Attribute.alpha = global::GUTSchedule.Droid.Resource.Attribute.alpha;
global::Xamarin.Essentials.Resource.Attribute.coordinatorLayoutStyle = global::GUT.Schedule.Resource.Attribute.coordinatorLayoutStyle; global::Xamarin.Essentials.Resource.Attribute.coordinatorLayoutStyle = global::GUTSchedule.Droid.Resource.Attribute.coordinatorLayoutStyle;
global::Xamarin.Essentials.Resource.Attribute.font = global::GUT.Schedule.Resource.Attribute.font; global::Xamarin.Essentials.Resource.Attribute.font = global::GUTSchedule.Droid.Resource.Attribute.font;
global::Xamarin.Essentials.Resource.Attribute.fontProviderAuthority = global::GUT.Schedule.Resource.Attribute.fontProviderAuthority; global::Xamarin.Essentials.Resource.Attribute.fontProviderAuthority = global::GUTSchedule.Droid.Resource.Attribute.fontProviderAuthority;
global::Xamarin.Essentials.Resource.Attribute.fontProviderCerts = global::GUT.Schedule.Resource.Attribute.fontProviderCerts; global::Xamarin.Essentials.Resource.Attribute.fontProviderCerts = global::GUTSchedule.Droid.Resource.Attribute.fontProviderCerts;
global::Xamarin.Essentials.Resource.Attribute.fontProviderFetchStrategy = global::GUT.Schedule.Resource.Attribute.fontProviderFetchStrategy; global::Xamarin.Essentials.Resource.Attribute.fontProviderFetchStrategy = global::GUTSchedule.Droid.Resource.Attribute.fontProviderFetchStrategy;
global::Xamarin.Essentials.Resource.Attribute.fontProviderFetchTimeout = global::GUT.Schedule.Resource.Attribute.fontProviderFetchTimeout; global::Xamarin.Essentials.Resource.Attribute.fontProviderFetchTimeout = global::GUTSchedule.Droid.Resource.Attribute.fontProviderFetchTimeout;
global::Xamarin.Essentials.Resource.Attribute.fontProviderPackage = global::GUT.Schedule.Resource.Attribute.fontProviderPackage; global::Xamarin.Essentials.Resource.Attribute.fontProviderPackage = global::GUTSchedule.Droid.Resource.Attribute.fontProviderPackage;
global::Xamarin.Essentials.Resource.Attribute.fontProviderQuery = global::GUT.Schedule.Resource.Attribute.fontProviderQuery; global::Xamarin.Essentials.Resource.Attribute.fontProviderQuery = global::GUTSchedule.Droid.Resource.Attribute.fontProviderQuery;
global::Xamarin.Essentials.Resource.Attribute.fontStyle = global::GUT.Schedule.Resource.Attribute.fontStyle; global::Xamarin.Essentials.Resource.Attribute.fontStyle = global::GUTSchedule.Droid.Resource.Attribute.fontStyle;
global::Xamarin.Essentials.Resource.Attribute.fontVariationSettings = global::GUT.Schedule.Resource.Attribute.fontVariationSettings; global::Xamarin.Essentials.Resource.Attribute.fontVariationSettings = global::GUTSchedule.Droid.Resource.Attribute.fontVariationSettings;
global::Xamarin.Essentials.Resource.Attribute.fontWeight = global::GUT.Schedule.Resource.Attribute.fontWeight; global::Xamarin.Essentials.Resource.Attribute.fontWeight = global::GUTSchedule.Droid.Resource.Attribute.fontWeight;
global::Xamarin.Essentials.Resource.Attribute.keylines = global::GUT.Schedule.Resource.Attribute.keylines; global::Xamarin.Essentials.Resource.Attribute.keylines = global::GUTSchedule.Droid.Resource.Attribute.keylines;
global::Xamarin.Essentials.Resource.Attribute.layout_anchor = global::GUT.Schedule.Resource.Attribute.layout_anchor; global::Xamarin.Essentials.Resource.Attribute.layout_anchor = global::GUTSchedule.Droid.Resource.Attribute.layout_anchor;
global::Xamarin.Essentials.Resource.Attribute.layout_anchorGravity = global::GUT.Schedule.Resource.Attribute.layout_anchorGravity; global::Xamarin.Essentials.Resource.Attribute.layout_anchorGravity = global::GUTSchedule.Droid.Resource.Attribute.layout_anchorGravity;
global::Xamarin.Essentials.Resource.Attribute.layout_behavior = global::GUT.Schedule.Resource.Attribute.layout_behavior; global::Xamarin.Essentials.Resource.Attribute.layout_behavior = global::GUTSchedule.Droid.Resource.Attribute.layout_behavior;
global::Xamarin.Essentials.Resource.Attribute.layout_dodgeInsetEdges = global::GUT.Schedule.Resource.Attribute.layout_dodgeInsetEdges; global::Xamarin.Essentials.Resource.Attribute.layout_dodgeInsetEdges = global::GUTSchedule.Droid.Resource.Attribute.layout_dodgeInsetEdges;
global::Xamarin.Essentials.Resource.Attribute.layout_insetEdge = global::GUT.Schedule.Resource.Attribute.layout_insetEdge; global::Xamarin.Essentials.Resource.Attribute.layout_insetEdge = global::GUTSchedule.Droid.Resource.Attribute.layout_insetEdge;
global::Xamarin.Essentials.Resource.Attribute.layout_keyline = global::GUT.Schedule.Resource.Attribute.layout_keyline; global::Xamarin.Essentials.Resource.Attribute.layout_keyline = global::GUTSchedule.Droid.Resource.Attribute.layout_keyline;
global::Xamarin.Essentials.Resource.Attribute.statusBarBackground = global::GUT.Schedule.Resource.Attribute.statusBarBackground; global::Xamarin.Essentials.Resource.Attribute.statusBarBackground = global::GUTSchedule.Droid.Resource.Attribute.statusBarBackground;
global::Xamarin.Essentials.Resource.Attribute.ttcIndex = global::GUT.Schedule.Resource.Attribute.ttcIndex; global::Xamarin.Essentials.Resource.Attribute.ttcIndex = global::GUTSchedule.Droid.Resource.Attribute.ttcIndex;
global::Xamarin.Essentials.Resource.Color.browser_actions_bg_grey = global::GUT.Schedule.Resource.Color.browser_actions_bg_grey; global::Xamarin.Essentials.Resource.Color.browser_actions_bg_grey = global::GUTSchedule.Droid.Resource.Color.browser_actions_bg_grey;
global::Xamarin.Essentials.Resource.Color.browser_actions_divider_color = global::GUT.Schedule.Resource.Color.browser_actions_divider_color; global::Xamarin.Essentials.Resource.Color.browser_actions_divider_color = global::GUTSchedule.Droid.Resource.Color.browser_actions_divider_color;
global::Xamarin.Essentials.Resource.Color.browser_actions_text_color = global::GUT.Schedule.Resource.Color.browser_actions_text_color; global::Xamarin.Essentials.Resource.Color.browser_actions_text_color = global::GUTSchedule.Droid.Resource.Color.browser_actions_text_color;
global::Xamarin.Essentials.Resource.Color.browser_actions_title_color = global::GUT.Schedule.Resource.Color.browser_actions_title_color; global::Xamarin.Essentials.Resource.Color.browser_actions_title_color = global::GUTSchedule.Droid.Resource.Color.browser_actions_title_color;
global::Xamarin.Essentials.Resource.Color.notification_action_color_filter = global::GUT.Schedule.Resource.Color.notification_action_color_filter; global::Xamarin.Essentials.Resource.Color.notification_action_color_filter = global::GUTSchedule.Droid.Resource.Color.notification_action_color_filter;
global::Xamarin.Essentials.Resource.Color.notification_icon_bg_color = global::GUT.Schedule.Resource.Color.notification_icon_bg_color; global::Xamarin.Essentials.Resource.Color.notification_icon_bg_color = global::GUTSchedule.Droid.Resource.Color.notification_icon_bg_color;
global::Xamarin.Essentials.Resource.Color.ripple_material_light = global::GUT.Schedule.Resource.Color.ripple_material_light; global::Xamarin.Essentials.Resource.Color.ripple_material_light = global::GUTSchedule.Droid.Resource.Color.ripple_material_light;
global::Xamarin.Essentials.Resource.Color.secondary_text_default_material_light = global::GUT.Schedule.Resource.Color.secondary_text_default_material_light; global::Xamarin.Essentials.Resource.Color.secondary_text_default_material_light = global::GUTSchedule.Droid.Resource.Color.secondary_text_default_material_light;
global::Xamarin.Essentials.Resource.Dimension.browser_actions_context_menu_max_width = global::GUT.Schedule.Resource.Dimension.browser_actions_context_menu_max_width; global::Xamarin.Essentials.Resource.Dimension.browser_actions_context_menu_max_width = global::GUTSchedule.Droid.Resource.Dimension.browser_actions_context_menu_max_width;
global::Xamarin.Essentials.Resource.Dimension.browser_actions_context_menu_min_padding = global::GUT.Schedule.Resource.Dimension.browser_actions_context_menu_min_padding; global::Xamarin.Essentials.Resource.Dimension.browser_actions_context_menu_min_padding = global::GUTSchedule.Droid.Resource.Dimension.browser_actions_context_menu_min_padding;
global::Xamarin.Essentials.Resource.Dimension.compat_button_inset_horizontal_material = global::GUT.Schedule.Resource.Dimension.compat_button_inset_horizontal_material; global::Xamarin.Essentials.Resource.Dimension.compat_button_inset_horizontal_material = global::GUTSchedule.Droid.Resource.Dimension.compat_button_inset_horizontal_material;
global::Xamarin.Essentials.Resource.Dimension.compat_button_inset_vertical_material = global::GUT.Schedule.Resource.Dimension.compat_button_inset_vertical_material; global::Xamarin.Essentials.Resource.Dimension.compat_button_inset_vertical_material = global::GUTSchedule.Droid.Resource.Dimension.compat_button_inset_vertical_material;
global::Xamarin.Essentials.Resource.Dimension.compat_button_padding_horizontal_material = global::GUT.Schedule.Resource.Dimension.compat_button_padding_horizontal_material; global::Xamarin.Essentials.Resource.Dimension.compat_button_padding_horizontal_material = global::GUTSchedule.Droid.Resource.Dimension.compat_button_padding_horizontal_material;
global::Xamarin.Essentials.Resource.Dimension.compat_button_padding_vertical_material = global::GUT.Schedule.Resource.Dimension.compat_button_padding_vertical_material; global::Xamarin.Essentials.Resource.Dimension.compat_button_padding_vertical_material = global::GUTSchedule.Droid.Resource.Dimension.compat_button_padding_vertical_material;
global::Xamarin.Essentials.Resource.Dimension.compat_control_corner_material = global::GUT.Schedule.Resource.Dimension.compat_control_corner_material; global::Xamarin.Essentials.Resource.Dimension.compat_control_corner_material = global::GUTSchedule.Droid.Resource.Dimension.compat_control_corner_material;
global::Xamarin.Essentials.Resource.Dimension.compat_notification_large_icon_max_height = global::GUT.Schedule.Resource.Dimension.compat_notification_large_icon_max_height; global::Xamarin.Essentials.Resource.Dimension.compat_notification_large_icon_max_height = global::GUTSchedule.Droid.Resource.Dimension.compat_notification_large_icon_max_height;
global::Xamarin.Essentials.Resource.Dimension.compat_notification_large_icon_max_width = global::GUT.Schedule.Resource.Dimension.compat_notification_large_icon_max_width; global::Xamarin.Essentials.Resource.Dimension.compat_notification_large_icon_max_width = global::GUTSchedule.Droid.Resource.Dimension.compat_notification_large_icon_max_width;
global::Xamarin.Essentials.Resource.Dimension.notification_action_icon_size = global::GUT.Schedule.Resource.Dimension.notification_action_icon_size; global::Xamarin.Essentials.Resource.Dimension.notification_action_icon_size = global::GUTSchedule.Droid.Resource.Dimension.notification_action_icon_size;
global::Xamarin.Essentials.Resource.Dimension.notification_action_text_size = global::GUT.Schedule.Resource.Dimension.notification_action_text_size; global::Xamarin.Essentials.Resource.Dimension.notification_action_text_size = global::GUTSchedule.Droid.Resource.Dimension.notification_action_text_size;
global::Xamarin.Essentials.Resource.Dimension.notification_big_circle_margin = global::GUT.Schedule.Resource.Dimension.notification_big_circle_margin; global::Xamarin.Essentials.Resource.Dimension.notification_big_circle_margin = global::GUTSchedule.Droid.Resource.Dimension.notification_big_circle_margin;
global::Xamarin.Essentials.Resource.Dimension.notification_content_margin_start = global::GUT.Schedule.Resource.Dimension.notification_content_margin_start; global::Xamarin.Essentials.Resource.Dimension.notification_content_margin_start = global::GUTSchedule.Droid.Resource.Dimension.notification_content_margin_start;
global::Xamarin.Essentials.Resource.Dimension.notification_large_icon_height = global::GUT.Schedule.Resource.Dimension.notification_large_icon_height; global::Xamarin.Essentials.Resource.Dimension.notification_large_icon_height = global::GUTSchedule.Droid.Resource.Dimension.notification_large_icon_height;
global::Xamarin.Essentials.Resource.Dimension.notification_large_icon_width = global::GUT.Schedule.Resource.Dimension.notification_large_icon_width; global::Xamarin.Essentials.Resource.Dimension.notification_large_icon_width = global::GUTSchedule.Droid.Resource.Dimension.notification_large_icon_width;
global::Xamarin.Essentials.Resource.Dimension.notification_main_column_padding_top = global::GUT.Schedule.Resource.Dimension.notification_main_column_padding_top; global::Xamarin.Essentials.Resource.Dimension.notification_main_column_padding_top = global::GUTSchedule.Droid.Resource.Dimension.notification_main_column_padding_top;
global::Xamarin.Essentials.Resource.Dimension.notification_media_narrow_margin = global::GUT.Schedule.Resource.Dimension.notification_media_narrow_margin; global::Xamarin.Essentials.Resource.Dimension.notification_media_narrow_margin = global::GUTSchedule.Droid.Resource.Dimension.notification_media_narrow_margin;
global::Xamarin.Essentials.Resource.Dimension.notification_right_icon_size = global::GUT.Schedule.Resource.Dimension.notification_right_icon_size; global::Xamarin.Essentials.Resource.Dimension.notification_right_icon_size = global::GUTSchedule.Droid.Resource.Dimension.notification_right_icon_size;
global::Xamarin.Essentials.Resource.Dimension.notification_right_side_padding_top = global::GUT.Schedule.Resource.Dimension.notification_right_side_padding_top; global::Xamarin.Essentials.Resource.Dimension.notification_right_side_padding_top = global::GUTSchedule.Droid.Resource.Dimension.notification_right_side_padding_top;
global::Xamarin.Essentials.Resource.Dimension.notification_small_icon_background_padding = global::GUT.Schedule.Resource.Dimension.notification_small_icon_background_padding; global::Xamarin.Essentials.Resource.Dimension.notification_small_icon_background_padding = global::GUTSchedule.Droid.Resource.Dimension.notification_small_icon_background_padding;
global::Xamarin.Essentials.Resource.Dimension.notification_small_icon_size_as_large = global::GUT.Schedule.Resource.Dimension.notification_small_icon_size_as_large; global::Xamarin.Essentials.Resource.Dimension.notification_small_icon_size_as_large = global::GUTSchedule.Droid.Resource.Dimension.notification_small_icon_size_as_large;
global::Xamarin.Essentials.Resource.Dimension.notification_subtext_size = global::GUT.Schedule.Resource.Dimension.notification_subtext_size; global::Xamarin.Essentials.Resource.Dimension.notification_subtext_size = global::GUTSchedule.Droid.Resource.Dimension.notification_subtext_size;
global::Xamarin.Essentials.Resource.Dimension.notification_top_pad = global::GUT.Schedule.Resource.Dimension.notification_top_pad; global::Xamarin.Essentials.Resource.Dimension.notification_top_pad = global::GUTSchedule.Droid.Resource.Dimension.notification_top_pad;
global::Xamarin.Essentials.Resource.Dimension.notification_top_pad_large_text = global::GUT.Schedule.Resource.Dimension.notification_top_pad_large_text; global::Xamarin.Essentials.Resource.Dimension.notification_top_pad_large_text = global::GUTSchedule.Droid.Resource.Dimension.notification_top_pad_large_text;
global::Xamarin.Essentials.Resource.Drawable.notification_action_background = global::GUT.Schedule.Resource.Drawable.notification_action_background; global::Xamarin.Essentials.Resource.Drawable.notification_action_background = global::GUTSchedule.Droid.Resource.Drawable.notification_action_background;
global::Xamarin.Essentials.Resource.Drawable.notification_bg = global::GUT.Schedule.Resource.Drawable.notification_bg; global::Xamarin.Essentials.Resource.Drawable.notification_bg = global::GUTSchedule.Droid.Resource.Drawable.notification_bg;
global::Xamarin.Essentials.Resource.Drawable.notification_bg_low = global::GUT.Schedule.Resource.Drawable.notification_bg_low; global::Xamarin.Essentials.Resource.Drawable.notification_bg_low = global::GUTSchedule.Droid.Resource.Drawable.notification_bg_low;
global::Xamarin.Essentials.Resource.Drawable.notification_bg_low_normal = global::GUT.Schedule.Resource.Drawable.notification_bg_low_normal; global::Xamarin.Essentials.Resource.Drawable.notification_bg_low_normal = global::GUTSchedule.Droid.Resource.Drawable.notification_bg_low_normal;
global::Xamarin.Essentials.Resource.Drawable.notification_bg_low_pressed = global::GUT.Schedule.Resource.Drawable.notification_bg_low_pressed; global::Xamarin.Essentials.Resource.Drawable.notification_bg_low_pressed = global::GUTSchedule.Droid.Resource.Drawable.notification_bg_low_pressed;
global::Xamarin.Essentials.Resource.Drawable.notification_bg_normal = global::GUT.Schedule.Resource.Drawable.notification_bg_normal; global::Xamarin.Essentials.Resource.Drawable.notification_bg_normal = global::GUTSchedule.Droid.Resource.Drawable.notification_bg_normal;
global::Xamarin.Essentials.Resource.Drawable.notification_bg_normal_pressed = global::GUT.Schedule.Resource.Drawable.notification_bg_normal_pressed; global::Xamarin.Essentials.Resource.Drawable.notification_bg_normal_pressed = global::GUTSchedule.Droid.Resource.Drawable.notification_bg_normal_pressed;
global::Xamarin.Essentials.Resource.Drawable.notification_icon_background = global::GUT.Schedule.Resource.Drawable.notification_icon_background; global::Xamarin.Essentials.Resource.Drawable.notification_icon_background = global::GUTSchedule.Droid.Resource.Drawable.notification_icon_background;
global::Xamarin.Essentials.Resource.Drawable.notification_template_icon_bg = global::GUT.Schedule.Resource.Drawable.notification_template_icon_bg; global::Xamarin.Essentials.Resource.Drawable.notification_template_icon_bg = global::GUTSchedule.Droid.Resource.Drawable.notification_template_icon_bg;
global::Xamarin.Essentials.Resource.Drawable.notification_template_icon_low_bg = global::GUT.Schedule.Resource.Drawable.notification_template_icon_low_bg; global::Xamarin.Essentials.Resource.Drawable.notification_template_icon_low_bg = global::GUTSchedule.Droid.Resource.Drawable.notification_template_icon_low_bg;
global::Xamarin.Essentials.Resource.Drawable.notification_tile_bg = global::GUT.Schedule.Resource.Drawable.notification_tile_bg; global::Xamarin.Essentials.Resource.Drawable.notification_tile_bg = global::GUTSchedule.Droid.Resource.Drawable.notification_tile_bg;
global::Xamarin.Essentials.Resource.Drawable.notify_panel_notification_icon_bg = global::GUT.Schedule.Resource.Drawable.notify_panel_notification_icon_bg; global::Xamarin.Essentials.Resource.Drawable.notify_panel_notification_icon_bg = global::GUTSchedule.Droid.Resource.Drawable.notify_panel_notification_icon_bg;
global::Xamarin.Essentials.Resource.Id.action_container = global::GUT.Schedule.Resource.Id.action_container; global::Xamarin.Essentials.Resource.Id.action_container = global::GUTSchedule.Droid.Resource.Id.action_container;
global::Xamarin.Essentials.Resource.Id.action_divider = global::GUT.Schedule.Resource.Id.action_divider; global::Xamarin.Essentials.Resource.Id.action_divider = global::GUTSchedule.Droid.Resource.Id.action_divider;
global::Xamarin.Essentials.Resource.Id.action_image = global::GUT.Schedule.Resource.Id.action_image; global::Xamarin.Essentials.Resource.Id.action_image = global::GUTSchedule.Droid.Resource.Id.action_image;
global::Xamarin.Essentials.Resource.Id.action_text = global::GUT.Schedule.Resource.Id.action_text; global::Xamarin.Essentials.Resource.Id.action_text = global::GUTSchedule.Droid.Resource.Id.action_text;
global::Xamarin.Essentials.Resource.Id.actions = global::GUT.Schedule.Resource.Id.actions; global::Xamarin.Essentials.Resource.Id.actions = global::GUTSchedule.Droid.Resource.Id.actions;
global::Xamarin.Essentials.Resource.Id.all = global::GUT.Schedule.Resource.Id.all; global::Xamarin.Essentials.Resource.Id.all = global::GUTSchedule.Droid.Resource.Id.all;
global::Xamarin.Essentials.Resource.Id.async = global::GUT.Schedule.Resource.Id.async; global::Xamarin.Essentials.Resource.Id.async = global::GUTSchedule.Droid.Resource.Id.async;
global::Xamarin.Essentials.Resource.Id.blocking = global::GUT.Schedule.Resource.Id.blocking; global::Xamarin.Essentials.Resource.Id.blocking = global::GUTSchedule.Droid.Resource.Id.blocking;
global::Xamarin.Essentials.Resource.Id.bottom = global::GUT.Schedule.Resource.Id.bottom; global::Xamarin.Essentials.Resource.Id.bottom = global::GUTSchedule.Droid.Resource.Id.bottom;
global::Xamarin.Essentials.Resource.Id.browser_actions_header_text = global::GUT.Schedule.Resource.Id.browser_actions_header_text; global::Xamarin.Essentials.Resource.Id.browser_actions_header_text = global::GUTSchedule.Droid.Resource.Id.browser_actions_header_text;
global::Xamarin.Essentials.Resource.Id.browser_actions_menu_item_icon = global::GUT.Schedule.Resource.Id.browser_actions_menu_item_icon; global::Xamarin.Essentials.Resource.Id.browser_actions_menu_item_icon = global::GUTSchedule.Droid.Resource.Id.browser_actions_menu_item_icon;
global::Xamarin.Essentials.Resource.Id.browser_actions_menu_item_text = global::GUT.Schedule.Resource.Id.browser_actions_menu_item_text; global::Xamarin.Essentials.Resource.Id.browser_actions_menu_item_text = global::GUTSchedule.Droid.Resource.Id.browser_actions_menu_item_text;
global::Xamarin.Essentials.Resource.Id.browser_actions_menu_items = global::GUT.Schedule.Resource.Id.browser_actions_menu_items; global::Xamarin.Essentials.Resource.Id.browser_actions_menu_items = global::GUTSchedule.Droid.Resource.Id.browser_actions_menu_items;
global::Xamarin.Essentials.Resource.Id.browser_actions_menu_view = global::GUT.Schedule.Resource.Id.browser_actions_menu_view; global::Xamarin.Essentials.Resource.Id.browser_actions_menu_view = global::GUTSchedule.Droid.Resource.Id.browser_actions_menu_view;
global::Xamarin.Essentials.Resource.Id.center = global::GUT.Schedule.Resource.Id.center; global::Xamarin.Essentials.Resource.Id.center = global::GUTSchedule.Droid.Resource.Id.center;
global::Xamarin.Essentials.Resource.Id.center_horizontal = global::GUT.Schedule.Resource.Id.center_horizontal; global::Xamarin.Essentials.Resource.Id.center_horizontal = global::GUTSchedule.Droid.Resource.Id.center_horizontal;
global::Xamarin.Essentials.Resource.Id.center_vertical = global::GUT.Schedule.Resource.Id.center_vertical; global::Xamarin.Essentials.Resource.Id.center_vertical = global::GUTSchedule.Droid.Resource.Id.center_vertical;
global::Xamarin.Essentials.Resource.Id.chronometer = global::GUT.Schedule.Resource.Id.chronometer; global::Xamarin.Essentials.Resource.Id.chronometer = global::GUTSchedule.Droid.Resource.Id.chronometer;
global::Xamarin.Essentials.Resource.Id.clip_horizontal = global::GUT.Schedule.Resource.Id.clip_horizontal; global::Xamarin.Essentials.Resource.Id.clip_horizontal = global::GUTSchedule.Droid.Resource.Id.clip_horizontal;
global::Xamarin.Essentials.Resource.Id.clip_vertical = global::GUT.Schedule.Resource.Id.clip_vertical; global::Xamarin.Essentials.Resource.Id.clip_vertical = global::GUTSchedule.Droid.Resource.Id.clip_vertical;
global::Xamarin.Essentials.Resource.Id.end = global::GUT.Schedule.Resource.Id.end; global::Xamarin.Essentials.Resource.Id.end = global::GUTSchedule.Droid.Resource.Id.end;
global::Xamarin.Essentials.Resource.Id.fill = global::GUT.Schedule.Resource.Id.fill; global::Xamarin.Essentials.Resource.Id.fill = global::GUTSchedule.Droid.Resource.Id.fill;
global::Xamarin.Essentials.Resource.Id.fill_horizontal = global::GUT.Schedule.Resource.Id.fill_horizontal; global::Xamarin.Essentials.Resource.Id.fill_horizontal = global::GUTSchedule.Droid.Resource.Id.fill_horizontal;
global::Xamarin.Essentials.Resource.Id.fill_vertical = global::GUT.Schedule.Resource.Id.fill_vertical; global::Xamarin.Essentials.Resource.Id.fill_vertical = global::GUTSchedule.Droid.Resource.Id.fill_vertical;
global::Xamarin.Essentials.Resource.Id.forever = global::GUT.Schedule.Resource.Id.forever; global::Xamarin.Essentials.Resource.Id.forever = global::GUTSchedule.Droid.Resource.Id.forever;
global::Xamarin.Essentials.Resource.Id.icon = global::GUT.Schedule.Resource.Id.icon; global::Xamarin.Essentials.Resource.Id.icon = global::GUTSchedule.Droid.Resource.Id.icon;
global::Xamarin.Essentials.Resource.Id.icon_group = global::GUT.Schedule.Resource.Id.icon_group; global::Xamarin.Essentials.Resource.Id.icon_group = global::GUTSchedule.Droid.Resource.Id.icon_group;
global::Xamarin.Essentials.Resource.Id.info = global::GUT.Schedule.Resource.Id.info; global::Xamarin.Essentials.Resource.Id.info = global::GUTSchedule.Droid.Resource.Id.info;
global::Xamarin.Essentials.Resource.Id.italic = global::GUT.Schedule.Resource.Id.italic; global::Xamarin.Essentials.Resource.Id.italic = global::GUTSchedule.Droid.Resource.Id.italic;
global::Xamarin.Essentials.Resource.Id.left = global::GUT.Schedule.Resource.Id.left; global::Xamarin.Essentials.Resource.Id.left = global::GUTSchedule.Droid.Resource.Id.left;
global::Xamarin.Essentials.Resource.Id.line1 = global::GUT.Schedule.Resource.Id.line1; global::Xamarin.Essentials.Resource.Id.line1 = global::GUTSchedule.Droid.Resource.Id.line1;
global::Xamarin.Essentials.Resource.Id.line3 = global::GUT.Schedule.Resource.Id.line3; global::Xamarin.Essentials.Resource.Id.line3 = global::GUTSchedule.Droid.Resource.Id.line3;
global::Xamarin.Essentials.Resource.Id.none = global::GUT.Schedule.Resource.Id.none; global::Xamarin.Essentials.Resource.Id.none = global::GUTSchedule.Droid.Resource.Id.none;
global::Xamarin.Essentials.Resource.Id.normal = global::GUT.Schedule.Resource.Id.normal; global::Xamarin.Essentials.Resource.Id.normal = global::GUTSchedule.Droid.Resource.Id.normal;
global::Xamarin.Essentials.Resource.Id.notification_background = global::GUT.Schedule.Resource.Id.notification_background; global::Xamarin.Essentials.Resource.Id.notification_background = global::GUTSchedule.Droid.Resource.Id.notification_background;
global::Xamarin.Essentials.Resource.Id.notification_main_column = global::GUT.Schedule.Resource.Id.notification_main_column; global::Xamarin.Essentials.Resource.Id.notification_main_column = global::GUTSchedule.Droid.Resource.Id.notification_main_column;
global::Xamarin.Essentials.Resource.Id.notification_main_column_container = global::GUT.Schedule.Resource.Id.notification_main_column_container; global::Xamarin.Essentials.Resource.Id.notification_main_column_container = global::GUTSchedule.Droid.Resource.Id.notification_main_column_container;
global::Xamarin.Essentials.Resource.Id.right = global::GUT.Schedule.Resource.Id.right; global::Xamarin.Essentials.Resource.Id.right = global::GUTSchedule.Droid.Resource.Id.right;
global::Xamarin.Essentials.Resource.Id.right_icon = global::GUT.Schedule.Resource.Id.right_icon; global::Xamarin.Essentials.Resource.Id.right_icon = global::GUTSchedule.Droid.Resource.Id.right_icon;
global::Xamarin.Essentials.Resource.Id.right_side = global::GUT.Schedule.Resource.Id.right_side; global::Xamarin.Essentials.Resource.Id.right_side = global::GUTSchedule.Droid.Resource.Id.right_side;
global::Xamarin.Essentials.Resource.Id.start = global::GUT.Schedule.Resource.Id.start; global::Xamarin.Essentials.Resource.Id.start = global::GUTSchedule.Droid.Resource.Id.start;
global::Xamarin.Essentials.Resource.Id.tag_transition_group = global::GUT.Schedule.Resource.Id.tag_transition_group; global::Xamarin.Essentials.Resource.Id.tag_transition_group = global::GUTSchedule.Droid.Resource.Id.tag_transition_group;
global::Xamarin.Essentials.Resource.Id.tag_unhandled_key_event_manager = global::GUT.Schedule.Resource.Id.tag_unhandled_key_event_manager; global::Xamarin.Essentials.Resource.Id.tag_unhandled_key_event_manager = global::GUTSchedule.Droid.Resource.Id.tag_unhandled_key_event_manager;
global::Xamarin.Essentials.Resource.Id.tag_unhandled_key_listeners = global::GUT.Schedule.Resource.Id.tag_unhandled_key_listeners; global::Xamarin.Essentials.Resource.Id.tag_unhandled_key_listeners = global::GUTSchedule.Droid.Resource.Id.tag_unhandled_key_listeners;
global::Xamarin.Essentials.Resource.Id.text = global::GUT.Schedule.Resource.Id.text; global::Xamarin.Essentials.Resource.Id.text = global::GUTSchedule.Droid.Resource.Id.text;
global::Xamarin.Essentials.Resource.Id.text2 = global::GUT.Schedule.Resource.Id.text2; global::Xamarin.Essentials.Resource.Id.text2 = global::GUTSchedule.Droid.Resource.Id.text2;
global::Xamarin.Essentials.Resource.Id.time = global::GUT.Schedule.Resource.Id.time; global::Xamarin.Essentials.Resource.Id.time = global::GUTSchedule.Droid.Resource.Id.time;
global::Xamarin.Essentials.Resource.Id.title = global::GUT.Schedule.Resource.Id.title; global::Xamarin.Essentials.Resource.Id.title = global::GUTSchedule.Droid.Resource.Id.title;
global::Xamarin.Essentials.Resource.Id.top = global::GUT.Schedule.Resource.Id.top; global::Xamarin.Essentials.Resource.Id.top = global::GUTSchedule.Droid.Resource.Id.top;
global::Xamarin.Essentials.Resource.Integer.status_bar_notification_info_maxnum = global::GUT.Schedule.Resource.Integer.status_bar_notification_info_maxnum; global::Xamarin.Essentials.Resource.Integer.status_bar_notification_info_maxnum = global::GUTSchedule.Droid.Resource.Integer.status_bar_notification_info_maxnum;
global::Xamarin.Essentials.Resource.Layout.browser_actions_context_menu_page = global::GUT.Schedule.Resource.Layout.browser_actions_context_menu_page; global::Xamarin.Essentials.Resource.Layout.browser_actions_context_menu_page = global::GUTSchedule.Droid.Resource.Layout.browser_actions_context_menu_page;
global::Xamarin.Essentials.Resource.Layout.browser_actions_context_menu_row = global::GUT.Schedule.Resource.Layout.browser_actions_context_menu_row; global::Xamarin.Essentials.Resource.Layout.browser_actions_context_menu_row = global::GUTSchedule.Droid.Resource.Layout.browser_actions_context_menu_row;
global::Xamarin.Essentials.Resource.Layout.notification_action = global::GUT.Schedule.Resource.Layout.notification_action; global::Xamarin.Essentials.Resource.Layout.notification_action = global::GUTSchedule.Droid.Resource.Layout.notification_action;
global::Xamarin.Essentials.Resource.Layout.notification_action_tombstone = global::GUT.Schedule.Resource.Layout.notification_action_tombstone; global::Xamarin.Essentials.Resource.Layout.notification_action_tombstone = global::GUTSchedule.Droid.Resource.Layout.notification_action_tombstone;
global::Xamarin.Essentials.Resource.Layout.notification_template_custom_big = global::GUT.Schedule.Resource.Layout.notification_template_custom_big; global::Xamarin.Essentials.Resource.Layout.notification_template_custom_big = global::GUTSchedule.Droid.Resource.Layout.notification_template_custom_big;
global::Xamarin.Essentials.Resource.Layout.notification_template_icon_group = global::GUT.Schedule.Resource.Layout.notification_template_icon_group; global::Xamarin.Essentials.Resource.Layout.notification_template_icon_group = global::GUTSchedule.Droid.Resource.Layout.notification_template_icon_group;
global::Xamarin.Essentials.Resource.Layout.notification_template_part_chronometer = global::GUT.Schedule.Resource.Layout.notification_template_part_chronometer; global::Xamarin.Essentials.Resource.Layout.notification_template_part_chronometer = global::GUTSchedule.Droid.Resource.Layout.notification_template_part_chronometer;
global::Xamarin.Essentials.Resource.Layout.notification_template_part_time = global::GUT.Schedule.Resource.Layout.notification_template_part_time; global::Xamarin.Essentials.Resource.Layout.notification_template_part_time = global::GUTSchedule.Droid.Resource.Layout.notification_template_part_time;
global::Xamarin.Essentials.Resource.String.status_bar_notification_info_overflow = global::GUT.Schedule.Resource.String.status_bar_notification_info_overflow; global::Xamarin.Essentials.Resource.String.status_bar_notification_info_overflow = global::GUTSchedule.Droid.Resource.String.status_bar_notification_info_overflow;
global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification = global::GUT.Schedule.Resource.Style.TextAppearance_Compat_Notification; global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification = global::GUTSchedule.Droid.Resource.Style.TextAppearance_Compat_Notification;
global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification_Info = global::GUT.Schedule.Resource.Style.TextAppearance_Compat_Notification_Info; global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification_Info = global::GUTSchedule.Droid.Resource.Style.TextAppearance_Compat_Notification_Info;
global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification_Line2 = global::GUT.Schedule.Resource.Style.TextAppearance_Compat_Notification_Line2; global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification_Line2 = global::GUTSchedule.Droid.Resource.Style.TextAppearance_Compat_Notification_Line2;
global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification_Time = global::GUT.Schedule.Resource.Style.TextAppearance_Compat_Notification_Time; global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification_Time = global::GUTSchedule.Droid.Resource.Style.TextAppearance_Compat_Notification_Time;
global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification_Title = global::GUT.Schedule.Resource.Style.TextAppearance_Compat_Notification_Title; global::Xamarin.Essentials.Resource.Style.TextAppearance_Compat_Notification_Title = global::GUTSchedule.Droid.Resource.Style.TextAppearance_Compat_Notification_Title;
global::Xamarin.Essentials.Resource.Style.Widget_Compat_NotificationActionContainer = global::GUT.Schedule.Resource.Style.Widget_Compat_NotificationActionContainer; global::Xamarin.Essentials.Resource.Style.Widget_Compat_NotificationActionContainer = global::GUTSchedule.Droid.Resource.Style.Widget_Compat_NotificationActionContainer;
global::Xamarin.Essentials.Resource.Style.Widget_Compat_NotificationActionText = global::GUT.Schedule.Resource.Style.Widget_Compat_NotificationActionText; global::Xamarin.Essentials.Resource.Style.Widget_Compat_NotificationActionText = global::GUTSchedule.Droid.Resource.Style.Widget_Compat_NotificationActionText;
global::Xamarin.Essentials.Resource.Style.Widget_Support_CoordinatorLayout = global::GUT.Schedule.Resource.Style.Widget_Support_CoordinatorLayout; global::Xamarin.Essentials.Resource.Style.Widget_Support_CoordinatorLayout = global::GUTSchedule.Droid.Resource.Style.Widget_Support_CoordinatorLayout;
global::Xamarin.Essentials.Resource.Xml.xamarin_essentials_fileprovider_file_paths = global::GUT.Schedule.Resource.Xml.xamarin_essentials_fileprovider_file_paths; global::Xamarin.Essentials.Resource.Xml.xamarin_essentials_fileprovider_file_paths = global::GUTSchedule.Droid.Resource.Xml.xamarin_essentials_fileprovider_file_paths;
global::Xamarin.Essentials.Resource.Styleable.ColorStateListItem = global::GUT.Schedule.Resource.Styleable.ColorStateListItem; global::Xamarin.Essentials.Resource.Styleable.ColorStateListItem = global::GUTSchedule.Droid.Resource.Styleable.ColorStateListItem;
global::Xamarin.Essentials.Resource.Styleable.ColorStateListItem_alpha = global::GUT.Schedule.Resource.Styleable.ColorStateListItem_alpha; global::Xamarin.Essentials.Resource.Styleable.ColorStateListItem_alpha = global::GUTSchedule.Droid.Resource.Styleable.ColorStateListItem_alpha;
global::Xamarin.Essentials.Resource.Styleable.ColorStateListItem_android_alpha = global::GUT.Schedule.Resource.Styleable.ColorStateListItem_android_alpha; global::Xamarin.Essentials.Resource.Styleable.ColorStateListItem_android_alpha = global::GUTSchedule.Droid.Resource.Styleable.ColorStateListItem_android_alpha;
global::Xamarin.Essentials.Resource.Styleable.ColorStateListItem_android_color = global::GUT.Schedule.Resource.Styleable.ColorStateListItem_android_color; global::Xamarin.Essentials.Resource.Styleable.ColorStateListItem_android_color = global::GUTSchedule.Droid.Resource.Styleable.ColorStateListItem_android_color;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_keylines = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_keylines; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_keylines = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_keylines;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_statusBarBackground = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_statusBarBackground; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_statusBarBackground = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_statusBarBackground;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_Layout; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_Layout;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_android_layout_gravity = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_Layout_android_layout_gravity; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_android_layout_gravity = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_Layout_android_layout_gravity;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_anchor = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_Layout_layout_anchor; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_anchor = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_Layout_layout_anchor;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_anchorGravity = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_Layout_layout_anchorGravity; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_anchorGravity = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_Layout_layout_anchorGravity;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_behavior = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_Layout_layout_behavior; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_behavior = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_Layout_layout_behavior;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_dodgeInsetEdges = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_Layout_layout_dodgeInsetEdges; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_dodgeInsetEdges = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_Layout_layout_dodgeInsetEdges;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_insetEdge = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_Layout_layout_insetEdge; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_insetEdge = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_Layout_layout_insetEdge;
global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_keyline = global::GUT.Schedule.Resource.Styleable.CoordinatorLayout_Layout_layout_keyline; global::Xamarin.Essentials.Resource.Styleable.CoordinatorLayout_Layout_layout_keyline = global::GUTSchedule.Droid.Resource.Styleable.CoordinatorLayout_Layout_layout_keyline;
global::Xamarin.Essentials.Resource.Styleable.FontFamily = global::GUT.Schedule.Resource.Styleable.FontFamily; global::Xamarin.Essentials.Resource.Styleable.FontFamily = global::GUTSchedule.Droid.Resource.Styleable.FontFamily;
global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderAuthority = global::GUT.Schedule.Resource.Styleable.FontFamily_fontProviderAuthority; global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderAuthority = global::GUTSchedule.Droid.Resource.Styleable.FontFamily_fontProviderAuthority;
global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderCerts = global::GUT.Schedule.Resource.Styleable.FontFamily_fontProviderCerts; global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderCerts = global::GUTSchedule.Droid.Resource.Styleable.FontFamily_fontProviderCerts;
global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderFetchStrategy = global::GUT.Schedule.Resource.Styleable.FontFamily_fontProviderFetchStrategy; global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderFetchStrategy = global::GUTSchedule.Droid.Resource.Styleable.FontFamily_fontProviderFetchStrategy;
global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderFetchTimeout = global::GUT.Schedule.Resource.Styleable.FontFamily_fontProviderFetchTimeout; global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderFetchTimeout = global::GUTSchedule.Droid.Resource.Styleable.FontFamily_fontProviderFetchTimeout;
global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderPackage = global::GUT.Schedule.Resource.Styleable.FontFamily_fontProviderPackage; global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderPackage = global::GUTSchedule.Droid.Resource.Styleable.FontFamily_fontProviderPackage;
global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderQuery = global::GUT.Schedule.Resource.Styleable.FontFamily_fontProviderQuery; global::Xamarin.Essentials.Resource.Styleable.FontFamily_fontProviderQuery = global::GUTSchedule.Droid.Resource.Styleable.FontFamily_fontProviderQuery;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont = global::GUT.Schedule.Resource.Styleable.FontFamilyFont; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_font = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_android_font; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_font = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_android_font;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_fontStyle = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_android_fontStyle; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_fontStyle = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_android_fontStyle;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_fontVariationSettings = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_android_fontVariationSettings; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_fontVariationSettings = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_android_fontVariationSettings;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_fontWeight = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_android_fontWeight; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_fontWeight = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_android_fontWeight;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_ttcIndex = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_android_ttcIndex; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_android_ttcIndex = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_android_ttcIndex;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_font = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_font; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_font = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_font;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_fontStyle = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_fontStyle; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_fontStyle = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_fontStyle;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_fontVariationSettings = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_fontVariationSettings; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_fontVariationSettings = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_fontVariationSettings;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_fontWeight = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_fontWeight; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_fontWeight = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_fontWeight;
global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_ttcIndex = global::GUT.Schedule.Resource.Styleable.FontFamilyFont_ttcIndex; global::Xamarin.Essentials.Resource.Styleable.FontFamilyFont_ttcIndex = global::GUTSchedule.Droid.Resource.Styleable.FontFamilyFont_ttcIndex;
global::Xamarin.Essentials.Resource.Styleable.GradientColor = global::GUT.Schedule.Resource.Styleable.GradientColor; global::Xamarin.Essentials.Resource.Styleable.GradientColor = global::GUTSchedule.Droid.Resource.Styleable.GradientColor;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_centerColor = global::GUT.Schedule.Resource.Styleable.GradientColor_android_centerColor; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_centerColor = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_centerColor;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_centerX = global::GUT.Schedule.Resource.Styleable.GradientColor_android_centerX; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_centerX = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_centerX;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_centerY = global::GUT.Schedule.Resource.Styleable.GradientColor_android_centerY; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_centerY = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_centerY;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_endColor = global::GUT.Schedule.Resource.Styleable.GradientColor_android_endColor; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_endColor = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_endColor;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_endX = global::GUT.Schedule.Resource.Styleable.GradientColor_android_endX; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_endX = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_endX;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_endY = global::GUT.Schedule.Resource.Styleable.GradientColor_android_endY; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_endY = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_endY;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_gradientRadius = global::GUT.Schedule.Resource.Styleable.GradientColor_android_gradientRadius; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_gradientRadius = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_gradientRadius;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_startColor = global::GUT.Schedule.Resource.Styleable.GradientColor_android_startColor; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_startColor = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_startColor;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_startX = global::GUT.Schedule.Resource.Styleable.GradientColor_android_startX; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_startX = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_startX;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_startY = global::GUT.Schedule.Resource.Styleable.GradientColor_android_startY; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_startY = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_startY;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_tileMode = global::GUT.Schedule.Resource.Styleable.GradientColor_android_tileMode; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_tileMode = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_tileMode;
global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_type = global::GUT.Schedule.Resource.Styleable.GradientColor_android_type; global::Xamarin.Essentials.Resource.Styleable.GradientColor_android_type = global::GUTSchedule.Droid.Resource.Styleable.GradientColor_android_type;
global::Xamarin.Essentials.Resource.Styleable.GradientColorItem = global::GUT.Schedule.Resource.Styleable.GradientColorItem; global::Xamarin.Essentials.Resource.Styleable.GradientColorItem = global::GUTSchedule.Droid.Resource.Styleable.GradientColorItem;
global::Xamarin.Essentials.Resource.Styleable.GradientColorItem_android_color = global::GUT.Schedule.Resource.Styleable.GradientColorItem_android_color; global::Xamarin.Essentials.Resource.Styleable.GradientColorItem_android_color = global::GUTSchedule.Droid.Resource.Styleable.GradientColorItem_android_color;
global::Xamarin.Essentials.Resource.Styleable.GradientColorItem_android_offset = global::GUT.Schedule.Resource.Styleable.GradientColorItem_android_offset; global::Xamarin.Essentials.Resource.Styleable.GradientColorItem_android_offset = global::GUTSchedule.Droid.Resource.Styleable.GradientColorItem_android_offset;
} }
public partial class Animation public partial class Animation

Before

Width:  |  Height:  |  Size: 129 KiB

After

Width:  |  Height:  |  Size: 129 KiB

@@ -14,7 +14,6 @@
<ProgressBar <ProgressBar
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="100dp" android:layout_height="100dp"
android:indeterminateTint="#fff"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:layout_margin="20dp"/> android:layout_margin="20dp"/>
@@ -23,7 +22,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/loadingStatus" android:text="@string/loadingStatus"
android:textColor="#fff" android:textColor="@android:color/white"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
/> />
</LinearLayout> </LinearLayout>
@@ -22,6 +22,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/appName" android:text="@string/appName"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:textColor="@android:color/white"
android:textSize="36dp"/> android:textSize="36dp"/>
<ProgressBar <ProgressBar
@@ -35,6 +36,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:textColor="@android:color/white"
android:text="@string/initializationStatus" android:text="@string/initializationStatus"
android:textSize="20dp"/> android:textSize="20dp"/>
</LinearLayout> </LinearLayout>
@@ -45,6 +47,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:textColor="@android:color/white"
android:text="v$(Build.BuildNumber) (ci-id #$(Build.BuildId))"/> android:text="v$(Build.BuildNumber) (ci-id #$(Build.BuildId))"/>
</RelativeLayout> </RelativeLayout>

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

@@ -47,7 +47,7 @@
<string name="addGroupToTitleCheckbox">Добавить номер группы в заголовок</string> <string name="addGroupToTitleCheckbox">Добавить номер группы в заголовок</string>
<string name="titleNote">(i) Не касается преподавательского расписания</string> <string name="titleNote">(i) Не касается преподавательского расписания</string>
<string name="destinationCalendarSpinner">Конечый календарь</string> <string name="destinationCalendarSpinner">Конечный календарь</string>
<string name="addScheduleButton">Добавить расписание</string> <string name="addScheduleButton">Добавить расписание</string>
@@ -37,7 +37,7 @@
<string name="forSemesterButton">For semester</string> <string name="forSemesterButton">For semester</string>
<string name="reminderSpinner">Set reminders for</string> <string name="reminderSpinner">Set reminders for</string>
<string name="reminderNote">(i) Attention, for cloud-based Google calendars Google automatically sets reminders for 30 minutes if there\'s no reminder set by user</string> <string name="reminderNote">(i) Attention, if you choose \"None\" for cloud-based Google calendars Google sets default reminder for events automatically sets reminders for 30 minutes if there\'s no reminder set by user</string>
<string name="noReminderOption">None</string> <string name="noReminderOption">None</string>
<string name="inTimeReminderOption">At the start of event</string> <string name="inTimeReminderOption">At the start of event</string>
<string name="fiveMinuteReminderOption">5 minutes</string> <string name="fiveMinuteReminderOption">5 minutes</string>
@@ -50,7 +50,7 @@
<string name="addScheduleButton">Add schedule</string> <string name="addScheduleButton">Add schedule</string>
<string name="copyrights">©2020 Michael Gordeev, INS, IS-907</string> <string name="copyrights">©2020 Michael Gordeev, INS, ICT-907</string>
<string name="clearCalendarOption">Clear schedule</string> <string name="clearCalendarOption">Clear schedule</string>
<string name="reportErrorOption">Report error</string> <string name="reportErrorOption">Report error</string>
@@ -79,7 +79,7 @@
<!-- AboutActivity --> <!-- AboutActivity -->
<string name="aboutTitle">About application</string> <string name="aboutTitle">About application</string>
<string name="appDescription">Application for SPbSUT professors\' and students\' schedule export</string> <string name="appDescription">Application for SPbSUT professors\' and students\' schedule export</string>
<string name="developedBy">Developed by Michael Gordeev (IS-907, INS) in the \"Technologies of Informational and Educational Systems\" Research Facility</string> <string name="developedBy">Developed by Michael Gordeev (ICT-907, INS) in the \"Technologies of Informational and Educational Systems\" Research Facility</string>
<string name="contributorsTitle">Contributors</string> <string name="contributorsTitle">Contributors</string>
<string name="specialThanksTitle">Special thanks</string> <string name="specialThanksTitle">Special thanks</string>
@@ -10,12 +10,11 @@
</style> </style>
<style name="AppTheme.Light.SplashScreen" parent="AppTheme.Light"> <style name="AppTheme.Light.SplashScreen" parent="AppTheme.Light">
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
<item name="android:navigationBarColor">@color/colorPrimary</item> <item name="android:navigationBarColor">@color/colorPrimary</item>
<item name="android:windowLightNavigationBar">false</item> <item name="android:windowLightNavigationBar">false</item>
<item name="android:windowBackground">@color/colorPrimary</item> <item name="android:windowBackground">@color/colorPrimary</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:indeterminateTint">@android:color/white</item> <item name="android:indeterminateTint">@android:color/white</item>
</style> </style>
</resources> </resources>
+24
View File
@@ -0,0 +1,24 @@
<Application
x:Class="GUTSchedule.UWP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
RequestedTheme="Light">
<Application.Resources>
<Style TargetType="Button">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Margin" Value="2"/>
</Style>
<Style TargetType="ComboBox">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="WrapWholeWords"/>
</Style>
<Style TargetType="CalendarDatePicker">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Margin" Value="2"/>
</Style>
<Color x:Key="SystemAccentColor">#ff8000</Color>
</Application.Resources>
</Application>
+56
View File
@@ -0,0 +1,56 @@
using System;
using System.Linq;
using Windows.ApplicationModel.Activation;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using GUTSchedule.UWP.Pages;
namespace GUTSchedule.UWP
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
sealed partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
if ((new string[] { "ua", "ru", "by", "kz", "kg", "md", "lv", "ee" }).Contains(Windows.System.UserProfile.GlobalizationPreferences.Languages[0].Split('-')[0]))
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "ru";
else
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "en";
InitializeComponent();
UnhandledException += OnError;
}
private async void OnError(object sender, UnhandledExceptionEventArgs e)
{
e.Handled = true;
await new MessageDialog(e.Message, e.GetType().ToString()).ShowAsync();
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
if (!(Window.Current.Content is Frame rootFrame))
Window.Current.Content = rootFrame = new Frame();
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
rootFrame.Navigate(typeof(MainPage), e.Arguments);
Window.Current.Activate();
}
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show More