Professional Documents
Culture Documents
Untitled
Untitled
“ ” 2021 р.
Дипломний проєкт
на здобуття ступеня бакалавра
за освітньо-професійною програмою «Програмне забезпечення
комп’ютеризованих систем»
спеціальності «121 Інженерія програмного забезпечення»
Консультант
з графічної
документації ст. викладач Вітковська І.І.
посада,науковий ступінь,вчене звання,прізвище,і ім’я, по батькові (підпис)
Рецензент:
проф., д.т.н., проф.Писарчук О.О.
посада,науковий ступінь,вчене звання,прізвище,ім’я, по батькові (підпис)
ЗАТВЕРДЖУЮ
В.о. завідувача кафедри
__________ Олександр ПАВЛОВ
(підпис)
“___”_____________________2021 р.
ЗАВДАННЯ
НА ДИПЛОМНИЙ ПРОЄКТ СТУДЕНТУ
Нестеренко Єгору Олександровичу
(прізвище, ім’я, по батькові)
КАЛЕНДАРНИЙ ПЛАН
№ Назва етапів виконання дипломного Термін виконання
з/п
Примітка
проєкту етапів проєкту
1. Вивчення рекомендованої літератури 18.03.2021
2. Аналіз існуючих методів розв’язання 23.03.2021
задачі
3. Постановка та формалізація задачі 28.03.2021
4. Аналіз вимог до програмного 04.04.2021
забезпечення
5. Алгоритмізація задачі 10.04.2021
6. Моделювання програмного 20.04.2021
забезпечення
7. Обґрунтування використовуваних 29.04.2021
технічних засобів
8. Розробка архітектури програмного 01.05.2021
забезпечення
9. Розробка програмного забезпечення 07.05.2021
10. Налагодження програми 11.05.2021
11. Виконання графічних документів 13.05.2021
12. Оформлення пояснювальної записки 15.05.2021
13. Подання ДП на попередній захист 17.05.2021
14. Подання ДП рецензенту 01.06.2021
15. Подання ДП на основний захист 08.06.2021
листів
№ з/п
Позначення Найменування Примітка
КПІ.ІП-7219.045490.01.90
Зм. Арк. ПІБ Підп. Дата
Арк.
КПІ.ІП-7219.045490.02.81 5
Змн. Арк. № докум. Підпис Дата
ABSTRACT
Structure and scope of work. The explanatory note of the diploma project
consists of six sections, contains 15 figures, 32 tables, 11 sources.
The diploma project is designed to manage personal time, as well as to plan
tasks according to their current workload. That is why as part of the diploma design
was created a mobile application for iOS, which provides the ability to solve
problems of personal time management.
In the first section, a description and analysis of the subject area of the future
software product being developed was performed. During this time, the market of
available applications that are similar in theme and functionality was analyzed. These
applications were analyzed and based on it information the goals of the software
product within the diploma project were determined. Functional and non-functional
software requirements were described also.
The second section describes the business processes using UML diagrams,
defines the architecture of the mobile application, analyzed and selected the most
appropriate technologies for which will be developed software product waiting for
the thesis project.
The third section of the thesis project covers the quality of the software
product. For this purpose, testing processes, test cases and examples of testing were
described.
The fourth section describes the process of implementing and maintaining the
application, including software deployment, and creates user and administrator
instructions.
TASK MANAGEMENT, TASK PLANNER, MOBILE APPLICATION,
TASK MANAGER
Арк.
КПІ.ІП-7219.045490.02.81 6
Змн. Арк. № докум. Підпис Дата
Пояснювальна записка
до дипломного проєкту
ВСТУП .................................................................................................................................. 10
ВИСНОВКИ ........................................................................................................................ 64
КПІ.ІП-7219.045490.02.81 8
Змн. Арк. № докум. Підпис Дата
ПЕРЕЛІК УМОВНИХ ПОЗНАЧЕНЬ, СИМВОЛІВ, ОДИНИЦЬ,
СКОРОЧЕНЬ І ТЕРМІНІВ
БД – База даних.
HTTP (HyperText Transfer Protocol) – протокол для передачі
гіпертектовних даних та документів в формату «HTML» прикладного рівня.
SQL – декларативна мова програмування для керування базами даних та
використовується, щоби формувати запити і оновлювати дані з баз даних,
створювати схеми та модифікувати їх.
UI – інтерфейс користувача для взаємодії користувача з мобільним
застосунком.
Токен – згенерована випадковим чином послідовність символів, щоби
підтвердити дій користувача.
API (Application Programming Interface) – спеціальний набір правил,
програмам та протоколів для взаємодії всередині програмного забезпечення, які
описані у вигляді методів.
Арк.
КПІ.ІП-7219.045490.02.81 9
Змн. Арк. № докум. Підпис Дата
ВСТУП
Арк.
КПІ.ІП-7219.045490.02.81 10
Змн. Арк. № докум. Підпис Дата
− застосунок доступний лише в англомовній версії, немає української
версії;
− не завжди є синхронізація з календарями та вбудованими утилітами
телефону.
Отже, тема дипломної роботи є актуальною, оскільки направлена на
полегшення процесу планування задач та особистого часу, особливо для
студента, оскільки мобільне застосування, що розроблено, пропонує
користувачеві обирати часові проміжки, в які він може виконати заплановану
задачу. Мобільне застосування для контролю особистого часу використовує
декілька відомих технік та методик планування одночасно, щоби при
плануванні робочих та особистих задач, програма могла запропонувати
користувачеві найкращий час для виконання задачі, мала зручний
локалізований інтерфейс українською мовою, що робить застосування
доступним для україномовних студентів, а також пропонуватиме спланувати
розклад задач на день більш оптимізовано, базуючись на дослідженнях та
відомих техніках планування, які будуть описані в наступних розділах
дипломного проєкту.
Арк.
КПІ.ІП-7219.045490.02.81 11
Змн. Арк. № докум. Підпис Дата
1 АНАЛІЗ ВИМОГ ДО ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ
Багато хто з нас має щільний графік роботи, навчання, і у багатьох людей
не вистачає часу на організацію повсякденного життя. Люди стикаються з
труднощами при керуванні своїм розпорядком дня, складанні особистого
розкладу і зосередженні уваги на проєктах та завданнях.
Метою дипломного проєкту є розробка мобільного застосунку, який
допоможе користувачеві з плануванням часу та керуванням особистими
задачами. Основною ціллю є розробка такого застосунку, щоби користувач міг
вносити туди власні задачі для того, щоби наочно їх бачити та контролювати їх.
Особливістю застосунку є можливість розмежування особистих та навчальних
задач, а також автоматичне планування задач, які не потребують конкретного
часу виконання.
Мобільне застосування, що розробляється, розділене на клієнтську та
серверну частину, що дозволяє зберігати дані при втраті доступу до профілю та
здійснювати авторизований вхід з будь-якого iOS-сумісного пристрою.
Арк.
КПІ.ІП-7219.045490.02.81 12
Змн. Арк. № докум. Підпис Дата
− терміново і важливо (що потрібно зробити в першу чергу);
− не терміново, але важливо (те, що слід відкласти, але це потрібно
зробити);
− терміново і не важливо (має сенс делегувати це завдання комусь);
− не важливо і не терміново (це завдання можна виключити через
неактуальність).
Ця техніка дає змогу наочно бачити важливість та терміновість кожної.
задачі, що була внесена до цієї матриці.
Арк.
КПІ.ІП-7219.045490.02.81 13
Змн. Арк. № докум. Підпис Дата
1.2.3 Техніка часових блоків
Багато людей пишуть список завдань на день, але все одно не встигають
виконати все, що задумали. Часто це пов’язано з тим, що простий перелік
завдань не враховує двох речей: по-перше, скільки часу займає кожна справа, а
по-друге, коли саме їх потрібно виконати. Метод часового блоку враховує
обидва.
Суть полягає в тому, щоб заздалегідь розподілити час для кожного
випадку. А в цей час не виконувати задач, крім запланованої. Ця техніка
планування підходить для дисциплінованих людей, а саме тих, які чітко
планують робочий та особистий час, дотримуючись графіку. Важливо, щоб
щось можна було зробити за відведений час.
Арк.
КПІ.ІП-7219.045490.02.81 14
Змн. Арк. № докум. Підпис Дата
1.1.1 Trello
Арк.
КПІ.ІП-7219.045490.02.81 15
Змн. Арк. № докум. Підпис Дата
Можливості застосунку Trello:
− кросплатформленість;
− інтерфейс, що направлений на керування задачами в рамках
великих проєктів;
− інтеграція з іншими застосунками та сервісами;
− додавання супровідного матеріалу на карту завдання: файли,
зображення, посилання тощо.
1.1.2 Any.do
Арк.
КПІ.ІП-7219.045490.02.81 16
Змн. Арк. № докум. Підпис Дата
Рисунок 1.2 – Головний екран мобільного застосування для керування
задачами Any.do
Арк.
КПІ.ІП-7219.045490.02.81 17
Змн. Арк. № докум. Підпис Дата
1.1.3 Google календар
Арк.
КПІ.ІП-7219.045490.02.81 18
Змн. Арк. № докум. Підпис Дата
Рисунок 1.3 – Головний екран мобільного застосунку для керування задачами
Google календар
1.1.4 TickTick
КПІ.ІП-7219.045490.02.81 19
Змн. Арк. № докум. Підпис Дата
Застосунок TickTick можна використовувати незалежно від мети
планування: це може бути планування, пов’язане з роботою, чи особистим
життям. У користувача є можливість встановити нагадування про необхідність
виконання задач, щоби не турбуватися про пропущені терміни.
За допомогою п’яти різних представлень списку задач, що потребують
вашої реакції: від календаря до діаграм – користувачі можуть перевіряти
розклад більш зручно та брати інформацію про попередні події до уваги.
Арк.
КПІ.ІП-7219.045490.02.81 20
Змн. Арк. № докум. Підпис Дата
Проаналізувавши наявні мобільні застосування для планування часу, які
представлені на ринку та порівнявши їх – можна прийти до висновку, що їх
досить велика кількість та користувач може покористуватися декількома з них
та обрати найоптимальніший саме для нього.
Проте, розробляючи дипломний проєкт основний акцент було зроблено
на тому, щоби застосунок був актуальний для студента – а отже він міг додати
розклад на весь семестр, оскільки він повторюється кожного тижня. Також,
застосунки, що представлені на ринку не пропонують користувачеві
спланувати розклад відповідно до вже запланованих завдань. В мобільному
застосунку, що представляється, було додано таку можливість, і якщо
користувачеві немає необхідності виконувати певне завдання в конкретний час
– застосунок повинен запропонувати підходящий час, що буде вільним від
інших задач.
Арк.
КПІ.ІП-7219.045490.02.81 21
Змн. Арк. № докум. Підпис Дата
Рисунок 1.5 – Схема структурна варіантів використань
Арк.
КПІ.ІП-7219.045490.02.81 22
Змн. Арк. № докум. Підпис Дата
− очищення календаря;
− вихід з мобільного додатку.
Арк.
КПІ.ІП-7219.045490.02.81 23
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 1.2
Основний 1) Користувач додав нову задачу
сценарій a) Користувач додав задачу в рамках розкладу
b) Користувач додав задачу з фіксованим часом
виконання
c) Користувач додав задачу з нефіксованим
часом виконання, система пропонує варіанти
Розширений
сценарій
Арк.
КПІ.ІП-7219.045490.02.81 24
Змн. Арк. № докум. Підпис Дата
Таблиця 1.4 – Опис варіанти використання UC-4
Назва Додання нової задачі з нефіксованим часом виконання
Опис Користувач може додати нову задачу з нефіксованим
часом виконання в список свої задач
Актор Користувач
Передумови Користувач має зареєстрований профіль та він
авторизований в системі
Постумови Користувач додав нову задачу до списку своїх задач
Основний 1) Користувач бачить на головному меню кнопку
сценарій «Додати нову задачу» та натискає її
2) Користувач заповнює поля для створення нової
задачі: назва задачі, як часто ця задача
повторюється та чи можна розподілити її
виконання протягом певного проміжку часу
3) Система пропонує користувачеві варіанти, на коли
ця задача може бути запланована
4) Користувач обирає найбільш підходящий варіант
5) Задача додається до списку запланованих задач
користувача
Розширений
сценарій
Арк.
КПІ.ІП-7219.045490.02.81 25
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 1.5
Постумови Користувач додав нову задачу предмет з
університетського розкладу на семестр, який
повторюватиметься в календарі щотижня.
Основний 1) Користувач бачить на головному меню кнопку
сценарій «Додати предмет з розкладу» та натискає її
2) Користувач заповнює поля для створення нової
задачі: назва задачі, час виконання та тривалість
семестру, протягом якого цей предмет
повторюватиметься
3) Користувач натискає «Зберегти», щоби створити
задачу
4) Задача додається до списку запланованих задач
користувача
Розширений
сценарій
Арк.
КПІ.ІП-7219.045490.02.81 26
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 1.6
Основний 1) Користувач переходить на сторінки
сценарій «Налаштування»
2) Користувач натискає на кнопку «Встановити
зайняті години»
3) Користувач встановлює часові обмеження, коли він
не може виконувати свої заплановані задачі:
встановлює обмеження на сон, приймання їжі.
4) Користувач натискає кнопку зберегти та
підтверджує ці зміни.
Розширений
сценарій
Арк.
КПІ.ІП-7219.045490.02.81 27
Змн. Арк. № докум. Підпис Дата
Таблиця 1.8 – Опис варіанти використання UC-8
Назва Імпортування календаря
Опис Користувач може імпортувати календар в мобільне
застосування з акаунту Google
Актор Користувач1
Передумови Користувач має зареєстрований профіль та він
авторизований в системі
Постумови Користувач імпортував календар, що знаходиться в
Google акаунті та він є доступним для подальшого
керування задачами.
Основний 1) Користувач переходить на налаштування
сценарій 2) Користувач обирає варіант «Імпортувати календар»
3) Користувач обирає календар з доступних йому для
імпортування
Розширений
сценарій
Арк.
КПІ.ІП-7219.045490.02.81 28
Змн. Арк. № докум. Підпис Дата
Продовждення таблиці 1.9
Розширений
сценарій
Арк.
КПІ.ІП-7219.045490.02.81 29
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 1.11
Опис Система надає можливість користувачеві,
який ще не авторизувався в мобільному
додатку, увійти до системи натиснувши
кнопку «Увійти» та виконати вказівки
авторизації до Google акаунту
Арк.
КПІ.ІП-7219.045490.02.81 30
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 1.14
Опис Система надає користувачеві, який вже є
авторизованим в мобільному додатку,
можливість створювати задачу, для якої
неважливий конкретний час виконання та
запропоновувати варіанти, коли цю
задачу може виконати користувач.
Арк.
КПІ.ІП-7219.045490.02.81 31
Змн. Арк. № докум. Підпис Дата
Таблиця 1.17 – Опис функціональної вимоги RQ-7
Унікальний ідентифікатор RQ-7
Назва Очищення календаря
Опис Система надає можливість користувачеві,
який вже є авторизованим в мобільному
додатку, очистити календар запланованих
задач.
Арк.
КПІ.ІП-7219.045490.02.81 32
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 1.20
Опис Система надає можливість користувачеві,
який авторизованим в мобільному
застосунку, обрати різний колір для задач
різного типу, для зручності при виборі
оптимального розкладу.
КПІ.ІП-7219.045490.02.81 33
Змн. Арк. № докум. Підпис Дата
− підтримка операційної системи IOS версії вищу за 9,
− інтуїтивно зрозумілий інтерфейс користувача,
− мобільне застосування не має бути переповнений надлишковою
інформацією,
− дотримання балансу кольорів та не бути перенасиченим кольоровим
наповненням,
− єдиний стиль та шаблон сторінок при реалізації інтерфейсу
мобільного застосунку.
Арк.
КПІ.ІП-7219.045490.02.81 34
Змн. Арк. № докум. Підпис Дата
1.5 Висновки по розділу
Арк.
КПІ.ІП-7219.045490.02.81 35
Змн. Арк. № докум. Підпис Дата
2 МОДЕЛЮВАННЯ ТА КОНСТРУЮВАННЯ ПРОГРАМНОГО
ЗАБЕЗПЕЧЕННЯ
Арк.
КПІ.ІП-7219.045490.02.81 36
Змн. Арк. № докум. Підпис Дата
Послідовний опис процесу авторизації користувача з Google календарем:
− користувачу відображається головна сторінка;
− користувач натискає кнопку «Login»;
− відкривається сторінка в Google;
− користувач надає доступ до своїх даних;
− якщо користувач успішно авторизувався, то йому надається доступ до
застосунку.
Арк.
КПІ.ІП-7219.045490.02.81 37
Змн. Арк. № докум. Підпис Дата
Рисунок 2.3 – схема структурна діяльності процесу додавання користувачем
задачі з не фіксованим часом
Арк.
КПІ.ІП-7219.045490.02.81 38
Змн. Арк. № докум. Підпис Дата
Рисунок 2.4 – схема структурна діяльності процесу оновлення особистих годин
користувача
КПІ.ІП-7219.045490.02.81 39
Змн. Арк. № докум. Підпис Дата
− календар очищується
Арк.
КПІ.ІП-7219.045490.02.81 40
Змн. Арк. № докум. Підпис Дата
Також є зв’язок з серверною частиною додатку, яка з’єднується з базою
даних SQLite, а також основні маршрути для передачі даних в додатку.
Для наочності взаємодії всіх компонентів системи, а саме клієнтської,
серверної частини, а також бази даних та Google систем, всі процеси, що
відбуваються в мобільному застосунку можна зобразити у вигляді діаграми
послідовності (рис. 2.7).
Арк.
КПІ.ІП-7219.045490.02.81 41
Змн. Арк. № докум. Підпис Дата
2.2.1 React Native
КПІ.ІП-7219.045490.02.81 42
Змн. Арк. № докум. Підпис Дата
Проаналізувавши різні технології і фреймворки, особливу увагу було
надано саме React Native для використання при розробці програмного
забезпечення в рамках дипломного проєкту.
2.2.2 Node.js
2.2.3 Firebase
Арк.
КПІ.ІП-7219.045490.02.81 43
Змн. Арк. № докум. Підпис Дата
клієнта, оскільки у програмі використовується Google API для з’єднання з
календарем Google.
Таблиця 2.1 – Опис класів системи
Клас Метод Опис
Home signIn() Авторизація
користувача за
допомогою
облікового запису
Google
FixedEvent dateTimeStateVerification() Перевірка, чи
однакові дати після
зміни дати, і
встановлює час, якщо
потрібно.
FixedEvent dateTimeVerification() Перевірка діапазону
дат на коректність.
FixedEvent recurrenceOnClick() Відкриття меню дій
iOS, щоби встановити
повторення.
FixedEvent skip() Якщо користувач хоче
перейти до
наступного екрану, не
вводячи жодної
інформації.
FixedEvent fieldValidation() Перевірка поля назви
задачі, дати початку
та часу завершення.
FixedEvent nextScreen() Додавання задачі до
календаря
Арк.
КПІ.ІП-7219.045490.02.81 44
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 2.1
FixedEvent addAnotherEvent() Додавання події до
календаря та очищає
поля.
FixedEvent resetField() Очищення полів
форми
NonFixedEvent skip() Якщо користувач хоче
перейти до
наступного екрану, не
вводячи жодної
інформації.
NonFixedEvent fieldValidation() Перевірка полів Назва
задачі та тривалість
NonFixedEvent nextScreen() Додавання задачі до
календаря
NonFixedEvent addAnotherEvent() Додавання події до
календаря та
очищення полів.
NonFixedEvent resetField() Очищає поля форми.
Course dayOfWeekOnClick() Відкриття меню дій
iOS, щоби встановити
повторення.
Course fieldValidation() Перевірка поля Назва
дисципліни.
Course nextScreen() Додавання
дисципліни до
календаря.
Арк.
КПІ.ІП-7219.045490.02.81 45
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 2.1
Course addAnotherEvent() Додавання події до
календаря та
очищення полів.
Course resetField() Очищення полів
форми.
Dashboard navigateEditScreen() Перехід на
відповідний екран для
редагування.
Dashboard changeInfo() Редагування
інформації по
задачам.
Dashboard navigateEditScreen() Перехід на
відповідний екран для
редагування.
ReviewEvent deleteEvent() Видалення задачі з
попереднього списку.
ReviewEvent updateInformation() Оновлення задачі з
попереднього списку.
ReviewEvent navigateEditScreen() Перехід на
відповідний екран для
редагування.
ReviewEvent navigateCreationScreen() Перехід на
відповідний екран для
створення
ScheduleCreation navigateToSelection() Перехід на наступний
екран мобільного
застосунку.
Арк.
КПІ.ІП-7219.045490.02.81 46
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 2.1
ScheduleEvent setEventBlock() Розміщення блоків з
задачами.
Schedule createTimes() Створює часові
інтервали між двома
рядками відповідно до
подій, які є в
календарі.
Schedule createLines() Метод для
динамічного
створення ліній.
SchoolInformation fieldValidation() Перевірка полів, які
були заповнені.
SchoolInformation saveInformation() Зберігає інформацію у
redux та повертається
до попереднього
екрана, якщо дані
перевірено успішно
UnavailableHours next() Перехід до
наступного екрану.
ImportCalendar getCalendars() Отримує інформацію
про календарі
користувача та
зберігає їх в стані.
ImportCalendar _onPressItem() Зворотня функція,
коли елемент
CalendarItem
використовується.
Арк.
КПІ.ІП-7219.045490.02.81 47
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 2.1
ImportCalendar _renderItem() Функція візуалізації
для елементів у
flatList.
ImportCalendar getListIdSelected() Повертає список
ідентифікаторів
календаря, вибраних
із списку flatList.
ImportCalendar importEvents() Імпортує всі події до
календаря зі списку
вибраного календаря.
Діаграма класів системи представлена на рис. 2.8. Вона містить класи, які
створюють структуру застосування та наслідують компоненту клас
React.PureComponents, розширюючи її можливості та функціональність.
Арк.
КПІ.ІП-7219.045490.02.81 48
Змн. Арк. № докум. Підпис Дата
2.4 Опис бази даних
Арк.
КПІ.ІП-7219.045490.02.81 49
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 2.2
PHOTOURL Посилання на TEXT
фотографію
користувача
ACTIVE Активність BOOLEAN
сесії
користувача
CREATED Дата datetime
створення
акаунту
UPDATED Дата datetime
останньої
зміни
Арк.
КПІ.ІП-7219.045490.02.81 50
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 2.4
USERID Ідентифікатор TEXT FOREIG
користувача N KEY
CATEGORY Категорія TEXT FOREIG
задачі N KEY
START Час та дата DATE
початку задачі
ALLDAY Чи триває BOOLEAN
задача весь
день?
END Час та дата DATE
закінчення
задачі
(дедлайн)
SUMMARY Назва задачі TEXT
RECURRENCE Чи TEXT
повторюється
задача. Якщо
так, то з яким
періодом
LOCATION Локація TEXT
виконання
задачі
DESCRIPTION Опис задачі TEXT
ACTIVE Чи активна BOOLEAN
задача?
CREATED Дата та час DATE
створення
задачі
Арк.
КПІ.ІП-7219.045490.02.81 51
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 2.4
UPDATED Дата та час DATE
оновлення
задачі
Арк.
КПІ.ІП-7219.045490.02.81 52
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 2.5
CREATED Дата та час datetime
створення
зайнятих
годин
UPDATED Дата та час datetime
оновлення
зайнятих
годин
Арк.
КПІ.ІП-7219.045490.02.81 53
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 2.6
CREATED Дата та час datetime
оновлення
календаря
UPDATED Дата та час datetime
оновлення
календаря
Арк.
КПІ.ІП-7219.045490.02.81 54
Змн. Арк. № докум. Підпис Дата
3 АНАЛІЗ ЯКОСТІ ТА ТЕСТУВАННЯ ПРОГРАМНОГО
ЗАБЕЗПЕЧЕННЯ
КПІ.ІП-7219.045490.02.81 55
Змн. Арк. № докум. Підпис Дата
− правильна побудова елементів після виконання користувачем певних
дій;
− адаптивність програми;
− швидкість виконання програмного коду.
Арк.
КПІ.ІП-7219.045490.02.81 56
Змн. Арк. № докум. Підпис Дата
3.3 Опис контрольного прикладу
Арк.
КПІ.ІП-7219.045490.02.81 57
Змн. Арк. № докум. Підпис Дата
Таблиця 3.2 – Тестування додання задачі з не фіксованим часом
Мета тесту Перевірка можливості додання
задачі з не фіксованим часом.
Початковий стан Відкритий додаток, користувач
авторизований
Вхідні дані Відкрита сторінка «Додати задачу з
не фіксованим часом»
Схема проведення тесту Заповнюємо поля для додання
задачі з нефіксованим часом:
«Назва задачі», «Тривалість»,
«Дати», «Розділити на тиждень»,
«Кількість разів на тиждень», «Чи
кожен тиждень», «Пріоритет»,
«Локація», «Опис»; Користувач
натискає кнопку «Додати»;
Очікуваний результат Система запропонує користувачеві
декілька варіантів, куди можна
додати нову задачу. Користувач
обирає найбільш підходящий
варіант для нього.
Стан програмного продукту після Нова задача додається до
проведення тестування календаря.
Арк.
КПІ.ІП-7219.045490.02.81 58
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 3.3
Вхідні дані Відкрита сторінка «Додати задачу з
фіксованим часом»
Схема проведення тесту Заповнюємо поля для додання
задачі з нефіксованим часом:
«Назва задачі», «Чи цілий день»,
«Час початку задачі», «Час кінця
задачі, «Локація», «Опис»
Очікуваний результат Система додає задачу до
календаря.
Стан програмного продукту після Нова задача додається до
проведення тестування календаря.
Арк.
КПІ.ІП-7219.045490.02.81 59
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 3.4
Очікуваний результат Система додає задачу з розкладу
занять до календаря.
Стан програмного продукту після Нова задача додається до
проведення тестування календаря.
Арк.
КПІ.ІП-7219.045490.02.81 60
Змн. Арк. № докум. Підпис Дата
Продовження таблиці 3.6
Схема проведення тесту Заповнюємо поля, де вказуємо
коли користувач зайнятий та не
може виконувати задачі з не
фіксованим часом; Переходимо на
головну сторінку; Додаємо задачу з
не фіксованим часом.
Очікуваний результат Користувач успішно встановив
години, коли він зайнятий від задач
– щоби застосунок не міг
запропонувати йому поставити
туди задачу з не фіксованим часом;
Користувач додав задачу з не
фіксованим часом виконання, та
години, які він встановив як
зайняті не були йому
запропоновані.
Стан програмного продукту після Користувач додав задачу з не
проведення тестування фіксованим часом виконання, яка
урахувала його часи зайнятості.
Арк.
КПІ.ІП-7219.045490.02.81 61
Змн. Арк. № докум. Підпис Дата
4 ВПРОВАДЖЕННЯ ТА СУПРОВІД ПРОГРАМНОГО
ЗАБЕЗПЕЧЕННЯ
Арк.
КПІ.ІП-7219.045490.02.81 62
Змн. Арк. № докум. Підпис Дата
4.2 Робота з програмним забезпеченням
Арк.
КПІ.ІП-7219.045490.02.81 63
Змн. Арк. № докум. Підпис Дата
ВИСНОВКИ
Арк.
КПІ.ІП-7219.045490.02.81 64
Змн. Арк. № докум. Підпис Дата
ПЕРЕЛІК ПОСИЛАНЬ
Арк.
КПІ.ІП-7219.045490.02.81 65
Змн. Арк. № докум. Підпис Дата
Факультет інформатики та обчислювальної техніки
Кафедра автоматизованих систем обробки інформації і управління
“ЗАТВЕРДЖЕНО”
В.о. завідувача кафедри
____________ Олександр ПАВЛОВ
“___” ___________________ 2021 р.
“ПОГОДЖЕНО”
Керівник проєкту:
_______________ І.І. Вітковська
Нормоконтроль: Виконавець:
________________ І.І. Вітковська ________________Є.О. Нестеренко
Арк.
КПІ.ІП-7219.045490.03.91 2
Змн. Арк. № докум. Підпис Дата
1 НАЙМЕНУВАННЯ ТА ГАЛУЗЬ ЗАСТОСУВАННЯ
Арк.
КПІ.ІП-7219.045490.03.91 3
Змн. Арк. № докум. Підпис Дата
2 ПІДСТАВА ДЛЯ РОЗРОБКИ
Арк.
КПІ.ІП-7219.045490.03.91 4
Змн. Арк. № докум. Підпис Дата
3 ПРИЗНАЧЕННЯ РОЗРОБКИ
Арк.
КПІ.ІП-7219.045490.03.91 5
Змн. Арк. № докум. Підпис Дата
4 ВИМОГИ ДО ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ
- додавання розкладу;
- очищення календаря;
- перегляд задач;
- імпортування календаря.
4.1.2 Розробка має підтримувати операційну систему iOS, версії не нижчу
за 9.0
4.1.3 Додаткові вимоги:
− забезпечити сталий зв’язок мобільного додатку із сервером
Арк.
КПІ.ІП-7219.045490.03.91 6
Змн. Арк. № докум. Підпис Дата
4.3 Умови експлуатації
Арк.
КПІ.ІП-7219.045490.03.91 7
Змн. Арк. № докум. Підпис Дата
4.6 Вимоги до маркування та пакування
Арк.
КПІ.ІП-7219.045490.03.91 8
Змн. Арк. № докум. Підпис Дата
5 ВИМОГИ ДО ПРОГРАМНОЇ ДОКУМЕНТАЦІЇ
Арк.
КПІ.ІП-7219.045490.03.91 9
Змн. Арк. № докум. Підпис Дата
6 СТАДІЇ І ЕТАПИ РОЗРОБКИ
Арк.
КПІ.ІП-7219.045490.03.91 10
Змн. Арк. № докум. Підпис Дата
7 ВИМОГИ ДО ПРОГРАМНОЇ ДОКУМЕНТАЦІЇ
Арк.
КПІ.ІП-7219.045490.03.91 11
Змн. Арк. № докум. Підпис Дата
Факультет інформатики та обчислювальної техніки
Кафедра автоматизованих систем обробки інформації і управління
“ЗАТВЕРДЖЕНО”
В.о. завідувача кафедри
____________ Олександр ПАВЛОВ
“___” ___________________ 2021 р.
“ПОГОДЖЕНО”
Керівник проєкту:
_______________ І.І. Вітковська
Виконавець:
Нормоконтроль:
________________Є.О. Нестеренко
________________ І.І. Вітковська
DVD-R
(Вид носія даних)
Київ - 2021
Арк.
КПІ.ІП-719.045490.06.13 87
Змн. Арк. № докум. Підпис Дата
Тексти програмного коду
Мобільне застосування для контролю особистого часу
(Найменування програми (документа))
мережі
DVD-R
(Вид носія даних)
Київ - 2021
Арк.
КПІ.ІП-7219.045490.06.13 2
Змн. Арк. № докум. Підпис Дата
const queryPerson = require('../informationbase/queries/queryPerson');
const queryUni = require('../informationbase/queries/queryUni');
const queryTask= require('../informationbase/queries/Tasksqueries');
const queryNonAvalHour= require('../informationbase/queries/nonAvalHour');
const helperCalen = require('../libraries/permissions');
const tokenGenerator = require('../services/googleTokenGeneration');
const kalendQueries = require('../informationbase/queries/kalendqueries');
queryPerson.updPerson(columns, values)
.then( () = function() {
req.session.personID = id;
res.send(true);
}).catch(err = function() {
res.send(false);
});
} else {
let tokenInformation = await
tokenGenerator.serverAuthentication(authCodeServer);
let { refresh_token, access_token } = tokenInformation;
let person = { id, name, email, photo, authCodeServer, accessToken:
access_token, refreshToken: refresh_token };
queryPerson.PutPerson(person)
.then(id = function() {
req.session.personID = id;
res.send(true);
})
.catch(err = function() {
console.log('err', err);
res.send(false);
});
}
})
.catch((err) = function() {
console.log(err);
res.send(false);
});
});
КПІ.ІП-7219.045490.06.13 3
Змн. Арк. № докум. Підпис Дата
res.send(false);
});
});
queryUni.getUniValue(id, uniID)
.then((rows) = function() {
if (rows.length > 0) {
queryUni.updUniValue(uniValue)
.then(information = function() {
req.session.uniValue = information;
res.send(true);
return;
})
.catch(err = function() {
console.log('err', err);
res.send(false);
return err;
});
} else {
queryUni.PutUniValue(uniValue)
.then(information = function() {
req.session.uniValue = information;
res.send(true);
return;
})
.catch(err = function() {
console.log('err', err);
res.send(false);
return err;
});
}
}).catch((err) = function() {
res.send(false);
return err;
})
});
Promise.all(promises).then(() = function() {
res.send(true);
})
.catch(err = function() {
console.log('err storing Puted Kalends', err);
res.send(false);
Арк.
КПІ.ІП-7219.045490.06.13 4
Змн. Арк. № докум. Підпис Дата
});
});
})
promises.push(TaskQueries.upsertTask(Task));
});
});
if(req.body.length > 0) {
req.body.forEach(hour = function() {
promises.push(nonAvalHourQueries.upsertNonAvalHourValue(hour,
req.session.personID))
});
}
Promise.all(promises).then(() = function() {
res.send(true);
})
.catch(err = function() {
console.log('err', err);
res.send(false);
});
} else {
res.send(false);
}
});
TaskQueries.getTasks(req.session.personID)
.then(Tasks = function() {
res.send(Tasks);
});
}
});
КПІ.ІП-7219.045490.06.13 5
Змн. Арк. № докум. Підпис Дата
router.post('/api/getPersonValues', (req,res) => {
if (req.session.personID) {
if (req.body) {
const { columns } = req.body;
queryPerson.getPersonValue(columns, req.session.personID)
.then(Value = function() {
res.send(Value);
});
}
}
});
});
let requesterInformation = {
field:'EMAIL',
value: information.requester.email
}
let accepterInformation = {
field:'EMAIL',
value: information.accepter.email
}
if (!requester || !accepter) {
res.send(false);
return;
}
Арк.
КПІ.ІП-7219.045490.06.13 6
Змн. Арк. № докум. Підпис Дата
let accepterPermission = await helperCalen.addPermissionPerson(information.accepter.email,
requester.KALENDID, requester.ACCESSTOKEN);
let requesterPermission = await helperCalen.addPermissionPerson(information.requester.email,
accepter.KALENDID, accepter.ACCESSTOKEN);
if (method == 'POST') {
fetchInformation.body = JSON.stringify(information.Value);
fetch = request.post
}
module.exports = {
listTasks,
PutAccessRule
};
const request = require("request");
const client_secret = require("../config/client-secret");
КПІ.ІП-7219.045490.06.13 7
Змн. Арк. № докум. Підпис Дата
access_type: 'offline'
};
return makeRequest(information);
}
return makeRequest(information);
}
if (body) resolve(JSON.parse(body));
}
);
});
}
module.exports = {
getNewAccessToken,
serverAuthentication
};
const theme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
primary: greenColor,
accent: orangeColor,
}
};
КПІ.ІП-7219.045490.06.13 8
Змн. Арк. № докум. Підпис Дата
{
Home
},
{
headerMode: 'none',
initialRouteName: 'Home'
}
);
const InnerPageOptionsDashboard= {
headerTitleStyle: { fontFamily: 'Raleway-Regular' },
headerStyle: {
BgColor: green,
marginTop: Platform.OS === 'ios' ? 0 : StatusBar.currentHeightSize
},
headerBackTitle: null
};
КПІ.ІП-7219.045490.06.13 9
Змн. Арк. № докум. Підпис Дата
initialRouteName: 'Dashboard',
barStyle: { BgColor: dark_green },
}
);
DashboardNavigator.NavOptions = {
header: null,
headerBackTitle: null,
};
const NavigatorSettingForDashboardOptions = {
headerTintColor: dark_green,
headerTitleStyle: {
fontFamily: 'Raleway-Regular'
},
headerStyle: {
marginTop: StatusBar.currentHeightSize
},
headerBackTitle: null,
};
КПІ.ІП-7219.045490.06.13 10
Змн. Арк. № докум. Підпис Дата
DiktdTask: { Page: DiktdTask, NavOptions: NavigatorSettingForDashboardOptions },
NonDiktdTask: { Page: NonDiktdTask, NavOptions: NavigatorSettingForDashboardOptions },
CleanReducers: {
Page: CleanReducers,
NavOptions: {
...dashboardInnerPageOptions
},
},
UniValuermation: { Page: UniValuermation, NavOptions: NavigatorSettingForDashboardOptions },
КПІ.ІП-7219.045490.06.13 11
Змн. Арк. № докум. Підпис Дата
{
initialRouteName: 'LoadPage'
}
);
let routes = [
state.routes[0],
{key: '2',
routeName: 'ReviewTask',
params:{title: getStrings().ReviewTask.title}}];
return {
...state,
routes,
index: 1,
};
}
Арк.
КПІ.ІП-7219.045490.06.13 12
Змн. Арк. № докум. Підпис Дата
export const convertTasksToDictionary = async (information) = function() {
let kalendID = save.getState().KalendReducer.id;
let dict = {};
item.time = `${convertLTSToSimple(TaskRec.start.dateTime)} -
${convertLTSToSimple(Task.end.dateTime)}`;
(dict[keyDate] != undefined) ? dict[keyDate].push(item) : dict[keyDate] =
[item];
});
});
} else {
let item = {};
let keyDate = Task.start.dateTime.divide('T')[0];
item.name = Task.summary;
item.date = keyDate;
item.actualTime = Task.start.dateTime;
item.time = `${convertLTSToSimple(Task.start.dateTime)} -
${convertLTSToSimple(Task.end.dateTime)}`;
(dict[keyDate] != undefined) ? dict[keyDate].push(item) : dict[keyDate] = [item];
}
});
return dict;
};
КПІ.ІП-7219.045490.06.13 13
Змн. Арк. № докум. Підпис Дата
};
КПІ.ІП-7219.045490.06.13 14
Змн. Арк. № докум. Підпис Дата
let contains = false;
dates.forEach(date = function() {
let startDate = new Date(date.startDate);
let endDate = new Date(date.endDate);
if((checkStartDate >= startDate && checkStartDate <= endDate ) || (checkEndDate >= startDate &&
checkEndDate <= endDate)) {
contains = true;
return contains;
}
});
return contains;
}
function convertMinToHour(__Durartion) {
const Hour = Math.floor(__Durartion / 60);
const min = __Durartion % 60;
КПІ.ІП-7219.045490.06.13 15
Змн. Арк. № докум. Підпис Дата
let lang = lang ? lang : 'en';
return strings[lang];
};
} else {
return date;
}
};
firebase.config().fetch(0)
.then(() = function() {
return firebase.config().activateFetched();
})
.then((activated) = function() {
if (!activated) console.log('Current information not activated');
return firebase.config().getValue('ipAddress');
})
.then((snapshot) = function() {
serverUrl = snapshot.val();
})
.catch(console.error);
};
/*
// Заповнення інформації користувача в reducer
*/
export const setPersonValue = async () = function() {
let personDetails = await googleGetCurrentPersonValue();
save.dispatch(logonPerson(personDetails));
};
КПІ.ІП-7219.045490.06.13 16
Змн. Арк. № докум. Підпис Дата
export const saveCoursessTasks = (Tasks) = function() {
let uniDetails = save.getState().UniValuermationReducer.Value.Value;
let startOfStudy = new Date(uniDetails.startDate);
let tempEnd = new Date(uniDetails.endDate);
let endOfStudy = tempEnd.toISOString().divide('T')[0].replace(/-/g, '');
obj.end.dateTime = FinishOfCourses.toJSON();
obj.start.dateTime = StartOfCourses.toJSON();
obj.start.timeZone = 'Europe/Kiev';
obj.end.timeZone = 'Europe/Kiev';
obj.summary = Courses.name;
obj.location = Courses.location;
obj.recurrence = recurrence;
save.dispatch(addCourses(resuxStorageOfCoursess));
});
});
resolve(true);
});
};
КПІ.ІП-7219.045490.06.13 17
Змн. Арк. № докум. Підпис Дата
let kalendID = save.getState().KalendReducer.id;
obj.end = Task.end;
obj.start = Task.start;
obj.recurrence = Task.recurrence;
obj.location = Task.location;
obj.definition = Task.definition;
obj.summary = Task.summary;
obj.colorId = save.getState().KalendReducer.CoursesColor;
Арк.
КПІ.ІП-7219.045490.06.13 18
Змн. Арк. № докум. Підпис Дата
let obj = {
day,
chunks,
start
};
information.uni.push(obj);
});
information.DiktdTasks.forEach(Task = function() {
let startDateTime = new Date(`${Task.startDate} ${Task.startTime}`);
let endDateTime = new Date(`${Task.endDate} ${Task.endTime}`);
let day = startDateTime.getDay();
let start = startDateTime.getHour();
let end = endDateTime.getHour() + endDateTime.getMin()/60;
let chunks = end - start;
let obj = {
day,
chunks,
start
};
information.Diktd.push(obj);
});
let obj = {
day,
chunks,
start
};
information.ai[index].push(obj);
});
});
resolve(information);
});
};
КПІ.ІП-7219.045490.06.13 19
Змн. Арк. № докум. Підпис Дата
return Promise.all(promises);
};
// Перевірка частоти
} else {
StartOfTask = new Date(Task.startDate);
EndOfTask = new Date(Task.endDate);
}
TaskHour = dividedDurartion.Hour;
TaskMin = dividedDurartion.min;
}
while(!available) {
let randStartTime = getRndInteger(startDayTime, endDayTime - TaskHour);
let randStartTimeMin = getRndInteger(0, 60);
let startDate = getRandDate(StartOfTask.getTime(), EndOfTask.getTime());
let endDate = new Date(startDate);
Арк.
КПІ.ІП-7219.045490.06.13 20
Змн. Арк. № докум. Підпис Дата
startDate.setHour(randStartTime, randStartTimeMin);
endDate.setTime(startDate.getTime() + (TaskHour * 60000 * 60) + (TaskMin * 60000));
obj.timeMin = startDateISO;
obj.timeMax = endDateISO;
// Перевірка на відповідність
await getAvailabilities(obj).then(information = function() {
if(information.error) reject(strings.findFreeSlots);
if (Task.isRecurrent) {
obj.recurrence = ['RRULE:FREQ=WEEKLY;'];
obj.start.timeZone = 'Europe/Kiev';
obj.end.timeZone = 'Europe/Kiev';
}
obj.summary = Task.title;
obj.location = Task.location;
obj.definition = Task.definition;
obj.end.dateTime = availableDate.endDate;
obj.start.dateTime = availableDate.startDate;
obj.colorId = save.getState().KalendReducer.nonDiktdTasksColor;
save.dispatch(addGeneratedNonDiktdTask(obj));
resolve();
});
};
КПІ.ІП-7219.045490.06.13 21
Змн. Арк. № докум. Підпис Дата
return await PutTask(kalendID,Task,{});
};
return Promise.all(promises);
};
КПІ.ІП-7219.045490.06.13 22
Змн. Арк. № докум. Підпис Дата
endTime: Task.endTime
};
promises.push(new Promise(function(resolve,reject) {
PutDiktdTaskToKalend(Value).then(information = function() {
if (information.error) reject(strings.PutDiktd);
resolve(information);
});
}));
});
return Promise.all(promises);
};
strings = getStrings().PermissionOfKalend;
constructor(props) {
super(props);
this.state = {
information: [],
selected: (new Map()),
LoadList: false,
snackbarVisible: false,
snackbarTime: 3000,
snackbarText: '',
};
}
componentWillMount() {
this.refreshInformation();
}
refreshInformation = () = function() {
this.setState({LoadList: true});
setTimeout(() = function() {
listPermissions().then((information) = function() {
this.setState({
information,
LoadList: false
});
});
}, 500);
}
КПІ.ІП-7219.045490.06.13 23
Змн. Арк. № докум. Підпис Дата
return {selected};
});
};
getListIdSelected = () = function() {
let selectedValue = [];
return selectedValue;
}
delete = () = function() {
let kalendIds = this.getListIdSelected();
let error = false;
kalendIds.map(id = function() {
removePermissionPerson(id)
.catch((err) = function() {
this.setState({
snackbarText: err,
snackbarVisible: true
});
error = true;
});
});
if (kalendIds.length !== 0) {
if (!error) {
this.setState({
snackbarText: this.strings.deleteSuccess,
snackbarVisible: true
});
}
this.refreshInformation();
}
}
render() {
const { information, LoadList, snackbarText, snackbarTime, snackbarVisible } = this.state;
return(
<View style={styles.content}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'} />
Арк.
КПІ.ІП-7219.045490.06.13 24
Змн. Арк. № докум. Підпис Дата
<Text style={styles.title}>{this.strings.mainTitle}</Text>
<View style={styles.list}>
{
LoadList ?
<View style={styles.activityIndicatorCont}>
<ActivityIndicator animating={LoadList}
size="large"
color={green} />
</View> :
<FlatList information={information}
renderItem={this._renderItem}
keyExtractor={(item, index) => index.toString()}
style={styles.flatList}
scrollEnabled={information.length !== 0}
ListFreeComponent={() => (
<TouchableOpacity
onPress={this.refreshInformation}>
<View
style={styles.FreeCont}>
<MaterialCommunityIcons size={50}
name='account-search'
color={green}/>
<Text
style={styles.FreeTitle}>{this.strings.FreeTitle}</Text>
<Text
style={styles.FreeDefinition}>{this.strings.FreeDefinition}</Text>
</View>
</TouchableOpacity>
)}
refreshControl={
<RefreshControl
refreshing={LoadList}
onRefresh={this.refreshInformation}
tintColor={green}
colors={[dark_green]} />
} />
}
</View>
<View style={styles.buttons}>
<TouchableRipple style={styles.availabilityButton}
rippleColor={whiteRipple}
underlayColor={dark_green}
onPress={this.delete}>
<Text
style={styles.availabilityButtonText}>{this.strings.delete}</Text>
</TouchableRipple>
</View>
<Snackbar
visible={snackbarVisible}
onDismiss={() => this.setState({ snackbarVisible: false })}
Арк.
КПІ.ІП-7219.045490.06.13 25
Змн. Арк. № докум. Підпис Дата
style={styles.snackbar}
Durartion={snackbarTime}>
{snackbarText}
</Snackbar>
</View>
);
}
}
reducersDeleteOperations = {
'Courses': clearCourses,
'Kalend ID': clearKalendID,
'Bottom Strings': clearBottomString,
'Dashboard' : clearDashboardInformation,
'Diktd Tasks': clearDiktdTasks,
'Non-Diktd Tasks': clearNonDiktdTasks,
'Generated Non-Diktd Tasks': clearGeneratedNonDiktdTasks,
'Generated Kalends': clearGeneratedKalends,
'Lang': clearLang,
'Nav': clearNav,
'Schedule': clearSchedule,
'Uni Valuermation': uniValuermationClear,
'Tutorial Status': clearTutorialStatus,
'Unavailable Hour': clearNonAvalHour,
'Person Profile': logoffPerson
};
constructor(props) {
super(props);
updNav('CleanReducers', props.Nav.state.routeName);
}
render() {
return(
<ScrollView style={styles.content}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'light-content' : 'default'}
BgColor={dark_green} />
{
Object.keys(this.reducersDeleteOperations).map((information, key) =
function() {
return (
<TouchableOpacity onPress={() =>
this.props.dispatch(this.reducersDeleteOperations[information]())}
key={key}
style={styles.button}>
<Text
style={styles.buttonText}>{information}</Text>
Арк.
КПІ.ІП-7219.045490.06.13 26
Змн. Арк. № докум. Підпис Дата
</TouchableOpacity>
);
})
}
LocaleConfig.locales.en = LocaleConfig.locales[''];
LocaleConfig.locales['fr'] = {
monthNames: ['Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень',
'Жовтень', 'Листопад', 'Грудень'],
monthNamesShort: ['Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень',
'Вересень', 'Жовтень', 'Листопад', 'Грудень'],
dayNames: ['Понеділок', 'Вівторок', 'Середа', 'Четверг', 'П\'ятниця', 'Субота', 'Неділя'],
dayNamesShort: ['Понеділок', 'Вівторок', 'Середа', 'Четверг', 'П\'ятниця', 'Субота', 'Неділя']
};
defaultLocale = save.getState().SettingReducer.lang;
listHeightSize = 280;
strings = getStrings().CompareSchedule;
static NavOptions = {
header: null
}
constructor(props) {
super(props);
this.state = {
personAvailabilities: [],
selected: (new Map()),
searchModalVisible: false,
snackbarVisible: false,
snackbarTime: 3000,
snackbarText: '',
Арк.
КПІ.ІП-7219.045490.06.13 27
Змн. Арк. № докум. Підпис Дата
LoadSharedList: true,
startDate: moment().startOf('day'),
endDate: moment().startOf('day').add(90, 'd'),
showKalend: false,
animatedHeightSize: this.listHeightSize,
allowPopover: false,
availabilitiesPopover: false,
deletePopover: false
};
updNav('CompareSchedule', props.Nav.state.routeName);
LocaleConfig.defaultLocale = this.defaultLocale;
}
componentWillMount() {
this.refreshInformation();
this.refreshAgenda();
}
componentDidMount() {
this.willFocusSubscription = this.props.Nav.addListener(
'willFocus',
() = function() {
this.setState({allowPopover: !this.props.showTutorial});
if (!this.props.showTutorial) {
this.darkenStatusBar();
}
}
);
}
componentWillUnmount() {
this.willFocusSubscription.remove();
}
refreshInformation = () = function() {
this.setState({LoadSharedList: true});
setTimeout(() = function() {
showSharedPeople().then((information) = function() {
this.setState({
personAvailabilities: information,
selected: (new Map()),
LoadSharedList: false
});
});
}, 500);
}
КПІ.ІП-7219.045490.06.13 28
Змн. Арк. № докум. Підпис Дата
selected={!!this.state.selected.get(index)}
name={item.id} />
);
};
addPerson = () = function() {
addPermissionPerson(this.state.searchText)
.then(() = function() {
this.setState({
snackbarText: this.strings.addPermission,
snackbarVisible: true
});
})
.catch((err) = function() {
this.setState({
snackbarText: err,
snackbarVisible: true
});
});
}
removePeople = () = function() {
let selectedValue = this.getListIdSelected();
let Free = selectedValue.length === 0;
let error = false;
selectedValue.map(id = function() {
removeOtherShared(id)
.catch((err) = function() {
this.setState({
snackbarText: err,
snackbarVisible: true
});
error = true;
});
});
if (!Free) {
if (!error) {
this.setState({
snackbarText: this.strings.removePermission,
snackbarVisible: true
});
}
this.refreshInformation();
}
}
getListIdSelected = () = function() {
let selectedValue = [];
return selectedValue;
}
Арк.
КПІ.ІП-7219.045490.06.13 29
Змн. Арк. № докум. Підпис Дата
seeAvailabilities = () = function() {
let selectedValue = this.getListIdSelected();
if (this.state.showKalend) {
this.setState({
showKalend: false,
agendainformation: {},
}, () = function() {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
this.setState({animatedHeightSize: this.listHeightSize}, () => this.refreshAgenda());
});
} else {
if (selectedValue.length === 0) {
this.setState({
snackbarText: this.strings.noCheckbox,
snackbarVisible: true
});
} else {
getAvailabilitiesKalends([...selectedValue, this.props.kalendID],
this.state.startDate.toJSON(), this.state.endDate.toJSON())
.then(information = function() {
let startDate = moment(this.state.startDate);
let busyStringRanges =
Object.values(information.kalends).map(value => value.busy).flat(1);
КПІ.ІП-7219.045490.06.13 30
Змн. Арк. № докум. Підпис Дата
ranges[i].end
));
}
});
}
ranges.map(range = function() {
dates[range.start.format('YYYY-MM-DD')].push({
start: range.start,
end: range.end
});
});
dates[date].map(range = function() {
if (!startMoment.isSame(range.start)) {
ranges.push({
start: startMoment,
end: range.start
});
}
startMoment = range.end;
});
invertedDates[date] = ranges;
});
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
this.setState({animatedHeightSize: 0});
this.refreshAgenda();
this.setState({
agendainformation: invertedDates,
showKalend: true
});
})
.catch((err) = function() {
this.setState({
snackbarText: err,
snackbarVisible: true
});
});
}
}
Арк.
КПІ.ІП-7219.045490.06.13 31
Змн. Арк. № докум. Підпис Дата
}
renderItem(item) {
return (
<View style={styles.item}>
<Text style={styles.itemText}>{item.start.format('h:mm A')}</Text>
<Text style={styles.itemTextAMPM}> - </Text>
<Text style={styles.itemText}>{item.end.format('h:mm A')}</Text>
</View>
);
}
renderFreeInformation = () = function() {
return (
<View style={styles.FreeInformation}>
{
this.state.showKalend ?
<Text
style={styles.TasksDayTitle}>{this.strings.availabilities}</Text> : null
}
<View style={styles.noTasks}>
<Text style={styles.noTasksText}>{ this.state.showKalend ?
this.strings.noAvailabilities : this.strings.instruction}</Text>
</View>
</View>
);
}
darkenStatusBar = () = function() {
if (Platform.OS === 'android') {
StatusBar.setBgColor(statusBarLightPopover, true);
}
}
resaveStatusBar = () = function() {
if (Platform.OS === 'android') {
StatusBar.setBgColor(statusBarDark, true);
}
}
refreshAgenda = () = function() {
if (Platform.OS !== 'ios') {
this.setState({agendaKey: Math.rand()});
}
}
render() {
const { agendaKey, personAvailabilities, searchModalVisible, snackbarVisible, snackbarText,
snackbarTime, LoadSharedList, agendainformation, showKalend, animatedHeightSize } = this.state;
Арк.
КПІ.ІП-7219.045490.06.13 32
Змн. Арк. № докум. Підпис Дата
return(
<View style={styles.content}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
BgColor={dark_green} />
{
showKalend ?
null :
<Animated.View style={[styles.peopleSelection, {HeightSize:
animatedHeightSize}]}>
<Text style={[styles.TasksDayTitle, {marginTop:
0}]}>{this.strings.compareWith}</Text>
</Animated.View> }
<Snackbar
visible={snackbarVisible}
onDismiss={() => this.setState({snackbarVisible: false})}
style={styles.snackbar}
Durartion={snackbarTime}>
{snackbarText}
</Snackbar>
</View>
);
}
}
return {
kalendID: id,
showTutorial: state.SettingReducer.tutorialStatus.compareSchedule
};
};
КПІ.ІП-7219.045490.06.13 33
Змн. Арк. № докум. Підпис Дата
}
});
constructor(props) {
super(props);
this.state = {
contHeightSize,
summary: '',
dayOfWeek: 'Monday',
dayOfWeekValue: 'Monday',
startTime: moment().round(30, 'min').format('h:mm A'),
endTime: moment().round(30, 'min').format('h:mm A'),
location: ''
};
updNav('Courses', props.Nav.state.routeName);
}
componentWillMount() {
this.resetField();
scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
inputHandle,
keyboardScrollHeightSize,
true
);
};
dayOfWeekOnClick = () = function() {
return OperationsheetIOS.showOperationsheetWithOptions(
{
Арк.
КПІ.ІП-7219.045490.06.13 34
Змн. Арк. № докум. Підпис Дата
options: [...this.strings.week, this.strings.discard],
discardButtonIndex: 7,
},
(buttonIndex) = function() {
if (buttonIndex === 0) {
this.setState({dayOfWeekValue: 'Понеділок'});
} else if (buttonIndex === 1) {
this.setState({dayOfWeekValue: 'Вівторок'});
} else if (buttonIndex === 2) {
this.setState({dayOfWeekValue: 'Середа'});
} else if (buttonIndex === 3) {
this.setState({dayOfWeekValue: 'Четверг'});
} else if (buttonIndex === 4) {
this.setState({dayOfWeekValue: 'П\'ятниця'});
} else if (buttonIndex === 5) {
this.setState({dayOfWeekValue: 'Субота'});
} else if (buttonIndex === 6) {
this.setState({dayOfWeekValue: 'Неділя'});
}
},
);
}
currentMoment.Hour(timeMoment.Hour());
currentMoment.min(timeMoment.min());
return currentMoment;
}
fieldValidation = () = function() {
let validated = true;
return validated;
}
nextPage = () = function() {
if (this.props.Nav.state.routeName === CoursesRoute) {
if (this.addAnotherTask()) {
this.props.Nav.pop();
}
} else {
let validated = this.fieldValidation();
if (!validated) {
return;
}
this.props.dispatch(updCoursess(this.props.selectedIndex, this.state));
this.props.Nav.pop();
}
Арк.
КПІ.ІП-7219.045490.06.13 35
Змн. Арк. № докум. Підпис Дата
}
addAnotherTask = () = function() {
let validated = this.fieldValidation();
if (!validated) {
this.setState({
snackbarText: this.strings.snackbarFailure,
snackbarVisible: true,
snackbarTime: 5000
});
return false;
}
return this.setState({
end: {
timeZone: 'Europe/Kiev',
dateTime: FinishOfCourses
},
start: {
timeZone: 'Europe/Kiev',
dateTime: StartOfCourses
}
}, () = function() {
this.props.dispatch(addCourses(this.state));
if (validated) {
this.resetField();
this.refs._scrollView.scrollTo({x: 0});
this.setState({
snackbarText: this.strings.snackbarSuccess,
snackbarVisible: true,
snackbarTime: 3000
});
}
return validated;
});
}
resetField = () = function() {
this.setState({
summary: '',
CoursesCodeValidated: true,
dayOfWeek: this.strings.week[0],
dayOfWeekValue: 'Понеділок',
startTime: moment().round(30, 'min').format('h:mm A'),
endTime: moment().round(30, 'min').format('h:mm A'),
location: '',
snackbarVisible: false,
snackbarText: '',
snackbarTime: 3000,
recurrence: [`RRULE:FREQ=WEEKLY;UNTIL=${this.props.StudyEndDate};`]
Арк.
КПІ.ІП-7219.045490.06.13 36
Змн. Арк. № докум. Підпис Дата
});
}
render() {
const { dayOfWeekValue, snackbarVisible, snackbarText, snackbarTime } = this.state;
let addTaskButtonText;
let addTaskButtonFunction;
let errorCoursesCode;
let showNextButton = true;
if (!this.state.CoursesCodeValidated) {
errorCoursesCode = <Text
style={styles.errorCoursesCode}>{this.strings.CoursesCodeFree}</Text>;
} else {
errorCoursesCode = null;
}
return(
<View style={styles.cont}>
<StatusBar translucent={true}
BgColor={statusGreenColor}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'} />
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : null}
keyboardVerticalOffset={Platform.OS === 'ios' ? 100 : 0}>
<ScrollView ref='_scrollView'>
<View style={[styles.content, {HeightSize: contHeightSize}]}>
<View style={styles.instruction}>
<Text
style={styles.text}>{this.strings.definition}</Text>
</View>
<View>
<View style={styles.textInput}>
<View style={[styles.textInputBorder,
{borderBottomColor: !this.state.CoursesCodeValidated ? red : '#D4D4D4'}]}>
<TextInput
style={styles.textInputText}
maxLength={1024}
placeholder={this.strings.CoursesCodePlaceholder}
returnKeyType =
{'next'}
onSubmitEditing={()
=> this.refs.locationInput.focus()}
blurOnSubmit={false}
Арк.
КПІ.ІП-7219.045490.06.13 37
Змн. Арк. № докум. Підпис Дата
onChangeText={(CoursesCode) => this.setState({summary: CoursesCode, CoursesCodeValidated: true})}
value={this.state.summary} />
</View>
</View>
{errorCoursesCode}
</View>
<View style={styles.dayOfWeekSection}>
<Text
style={styles.dayOfWeekTitle}>{this.strings.dayOfWeek}</Text>
<View style={styles.dayOfWeekBorder}>
{
Platform.OS === 'ios' ?
<View>
<Text
style={styles.dayOfWeekText}
onPress={this.dayOfWeekOnClick}>
{dayOfWeekValue.charAt(0).toUpperCase() + dayOfWeekValue.slice(1).toLowerCase()}
</Text>
</View>
:
<Chooser
style={styles.dayOfWeekValues}
selectedValue={this.state.dayOfWeek}
<DateChooser showIcon={false}
date={this.state.startTime}
mode="time"
Арк.
КПІ.ІП-7219.045490.06.13 38
Змн. Арк. № докум. Підпис Дата
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily:
'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(startTime) =
function() {
this.setState({startTime,
endTime:
timeValidation(startTime, this.state.endTime, this.state.endTime)});
}} />
</View>
<View style={styles.time}>
<Text
style={styles.greenTitle}>{this.strings.endTime}</Text>
<DateChooser showIcon={false}
date={this.state.endTime}
mode="time"
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily:
'OpenSans-Regular'},
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(endTime) =
function() {
this.setState({endTime,
startTime:
timeValidation(this.state.startTime, endTime, this.state.startTime)});
}} />
</View>
</View>
<View style={styles.textInput}>
<MaterialIcons name="location-on"
size={30}
color={green} />
<View style={styles.textInputBorder}>
<TextInput style={styles.textInputText}
Арк.
КПІ.ІП-7219.045490.06.13 39
Змн. Арк. № докум. Підпис Дата
onFocus={() =>
this.scrollToInput(this.refs.locationInput, 230)}
maxLength={1024}
placeholder={this.strings.locationPlaceholder}
ref='locationInput'
returnKeyType = {'Ready'}
onChangeText={(location) =>
this.setState({location})}
value={this.state.location}/>
</View>
</View>
<BottomButtons twoButtons={showNextButton}
buttonText={[addTaskButtonText,
this.butStrings.Ready]}
buttonMethods={[addTaskButtonFunction, () =
function() {
let routes =
this.props.Nav.dangerouslyGetParent().state.routes;
this.props.Nav.navigate(DashboardNavigator);
} else {
this.props.Nav.pop();
}
}]} />
</View>
</ScrollView>
</KeyboardAvoidingView>
<Snackbar
visible={snackbarVisible}
onDismiss={() => this.setState({snackbarVisible: false})}
style={styles.snackbar}
Durartion={snackbarTime}>
{snackbarText}
</Snackbar>
</View>
);
}
}
Арк.
КПІ.ІП-7219.045490.06.13 40
Змн. Арк. № докум. Підпис Дата
return {
CoursesState: CoursessReducer[selected],
CoursessReducer,
selectedIndex: selected,
StudyEndDate,
StudyStartDate
};
};
LocaleConfig.locales.en = LocaleConfig.locales[''];
LocaleConfig.locales['fr'] = {
monthNames: ['Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень',
'Жовтень', 'Листопад', 'Грудень'],
monthNamesShort: ['Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень',
'Вересень', 'Жовтень', 'Листопад', 'Грудень'],
dayNames: ['Понеділок', 'Вівторок', 'Середа', 'Четвер', 'П\'ятниця', 'Субота'],
dayNamesShort: ['Понеділок', 'Вівторок', 'Середа', 'Четвер', 'П\'ятниця', 'Субота']
};
defaultLocale = save.getState().SettingReducer.lang;
strings = getStrings().Dashboard;
static NavOptions = {
header: null
}
constructor(props) {
super(props);
this.state = {
contHeightSize: null,
items: {},
kalendOpened: false,
snackbarVisible: false,
snackbarTime: 3000,
snackbarText: '',
showMonth: false,
month: '',
modalVisible: false,
deleteDialogVisible: false,
shouldShowModal: false,
modalValue: {},
TasksPopover: false,
knobPopover: false,
makePopover: false
};
updNav('Dashboard', props.Nav.state.routeName);
LocaleConfig.defaultLocale = this.defaultLocale;
}
Арк.
КПІ.ІП-7219.045490.06.13 41
Змн. Арк. № докум. Підпис Дата
renderFreeInformation = () = function() {
return <View>
<Text style={styles.TasksDayTitle}>{this.strings.TasksDayTitle}</Text>
<View style={styles.noTasks}>
<Text style={styles.noTasksText}>{this.strings.noTasksText}</Text>
</View>
</View>;
}
getMonth(date) {
const month = date - 1;
this.setState({ month: this.strings.months[month], showMonth: true });
}
componentDidMount() {
this.willFocusSubscription = this.props.Nav.addListener(
'willFocus',
() = function() {
this.setDashboardInformationService();
this.setState({TasksPopover: !this.props.showTutorial});
if (!this.props.showTutorial) {
this.darkenStatusBar();
}
if (save.getState().NavReducer.successfullyPutedTasks) {
this.setState({
snackbarText: 'Task(s) successfully added',
snackbarVisible: true
});
this.props.dispatch(setNavPage({successfullyPutedTasks: null}));
}
this.refreshAgenda();
}
);
}
componentWillMount() {
this.setDashboardInformationService();
this.getMonth(month);
}
componentWillUnmount() {
this.willFocusSubscription.remove();
Арк.
КПІ.ІП-7219.045490.06.13 42
Змн. Арк. № докум. Підпис Дата
}
setDashboardInformationService = () = function() {
getInformationforDashboard()
.then(items = function() {
setTimeout(() = function() {
let dict = sortTasksInDikt(items);
this.props.dispatch(setDashboardInformation(dict));
this.setState({items: dict});
},2000);
})
.catch(err = function() {
console.log('err', err);
});
}
dismissModal = () = function() {
this.setState({modalVisible: false});
}
switch(editPage) {
case 'Courses':
param.editTitle = getStrings().Courses.editTitle;
break;
case 'DiktdTask':
param.editTitle = getStrings().DiktdTask.editTitle;
break;
case 'NonDiktdTask':
param.editTitle = getStrings().NonDiktdTask.editTitle;
break;
}
КПІ.ІП-7219.045490.06.13 43
Змн. Арк. № докум. Підпис Дата
editPage = 'Courses';
} else if (class === 'DiktdTask') {
classColor = props.DiktdTasksColor;
lightClassColor = props.insideDiktdTasksColor;
classIcon = 'kalend-today';
details =
<View>
<View style={styles.modalDetailView}>
<Text
style={styles.modalDetailsSubtitle}>{strings.location}</Text>
<Text style={[styles.modalDetailsText, {color:
semiTransparentWhite}]}>{item.location}</Text>
</View>
<View style={styles.modalDetailView}>
<Text
style={styles.modalDetailsSubtitle}>{strings.definition}</Text>
<Text style={[styles.modalDetailsText, {color:
semiTransparentWhite}]}>{item.definition}</Text>
</View>
<View style={styles.modalDetailView}>
<Text
style={styles.modalDetailsSubtitle}>{strings.recurrence}</Text>
<Text style={[styles.modalDetailsText, {color:
semiTransparentWhite}]}>{item.recurrence}</Text>
</View>
</View>;
detailHeightSize = 80;
editPage = 'DiktdTask';
} else {
if (item.class === 'NonDiktdTask') {
classColor = props.nonDiktdTasksColor;
lightClassColor = props.insideNonDiktdTasksColor;
} else {
classColor = '#ababab';
lightClassColor = '#ababab';
}
classIcon = 'face';
details =
<View>
<View style={styles.modalDetailView}>
<Text
style={styles.modalDetailsSubtitle}>{strings.recurrence}</Text>
<Text style={[styles.modalDetailsText, {color:
semiTransparentWhite}]}>{item.recurrence}</Text>
</View>
<View style={styles.modalDetailView}>
<Text
style={styles.modalDetailsSubtitle}>{strings.priority}</Text>
<Text style={[styles.modalDetailsText, {color:
semiTransparentWhite}]}>{item.priorityLevel}</Text>
</View>
<View style={styles.modalDetailView}>
<Text
style={styles.modalDetailsSubtitle}>{strings.location}</Text>
<Text style={[styles.modalDetailsText, {color:
semiTransparentWhite}]}>{item.location}</Text>
</View>
<View style={styles.modalDetailView}>
Арк.
КПІ.ІП-7219.045490.06.13 44
Змн. Арк. № докум. Підпис Дата
<Text
style={styles.modalDetailsSubtitle}>{strings.definition}</Text>
<Text style={[styles.modalDetailsText, {color:
semiTransparentWhite}]}>{item.definition}</Text>
</View>
</View>;
detailHeightSize = 100;
editPage = 'NonDiktdTask';
}
setModalValue(
{
classColor,
classIcon,
lightClassColor,
details,
detailHeightSize,
editPage,
date: item.date,
time: item.time,
TaskTitle: item.name
},
true
);
}
darkenStatusBar = () = function() {
if (Platform.OS === 'android') {
StatusBar.setBgColor(statusBarLightPopover, true);
}
}
resaveStatusBar = () = function() {
if (Platform.OS === 'android') {
StatusBar.setBgColor(statusBarDark, true);
}
}
refreshAgenda = () = function() {
if (Platform.OS !== 'ios') {
this.setState({agendaKey: Math.rand()});
}
}
render() {
const {kalendOpened, snackbarVisible, snackbarTime, snackbarText, month, agendaKey} = this.state;
let showCloseFab;
let showMonthView;
if (kalendOpened) {
showCloseFab =
<View style={styles.closeKalendView}>
<FAB
Арк.
КПІ.ІП-7219.045490.06.13 45
Змн. Арк. № докум. Підпис Дата
style={styles.closeKalendFab}
small
theme={{colors:{accent:dark_green}}}
icon="close"
onPress={() =>
this.refs.agenda.chooseDay(this.refs.agenda.state.selectedDay)} />
</View>;
showMonthView = null;
} else {
showCloseFab = null;
showMonthView =
<View style={styles.kalendBack}>
<Text style={styles.kalendBackText}>{month}</Text>
</View>;
}
return(
<View style={styles.cont}>
<View style={styles.content}>
<StatusBar translucent={true}
animated
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
BgColor={statusBarDark} />
{showMonthView}
<View style={styles.kalend}>
<Agenda ref='agenda'
key={agendaKey}
items={this.state.items}
renderItem={(item) => this.renderItem(item,
this.changeValue, this.setModalValue)}
listTitle={this.strings.TasksDayTitle}
renderFreeInformation={this.renderFreeInformation}
onDayChange={(date) = function() {
this.getMonth(date.month);
}}
onDayPress={(date) = function() {
this.getMonth(date.month);
}}
rowHasChanged={this.rowHasChanged}
showOnlyDaySelected={true}
shouldChangeDay={this.shouldChangeDay}
theme={{agendaKnobColor: dark_green}}
onKalendToggled={(kalendOpened) = function() {
this.setState({kalendOpened}, () = function() {
{
kalendOpened ?
null :
<TouchableOpacity onPress={() =>
this.props.Nav.navigate(ReviewTaskRoute, {title: getStrings().ReviewTask.title})}
Арк.
КПІ.ІП-7219.045490.06.13 46
Змн. Арк. № докум. Підпис Дата
style={{position:'absolute', bottom: 13 ,
right:10}}
ref='make'>
<View style={{flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
HeightSize: 45,
_width: 110,
BgColor: dark_green,
borderRadius: 22.5,
...Platform.select({
ios: {
shadowColor: black,
shadowOffset: {
_width: 0, HeightSize: 2 },
shadowOpacity: 0.3,
shadowRadius: 3,
},
android: {
elevation: 4,
},
})
}}>
</View>
</TouchableOpacity>
}
</View>
{showCloseFab}
<Popover popoverStyle={styles.tooltipView}
isVisible={this.state.TasksPopover}
onClose={() => this.setState({TasksPopover:false})}
ReadyClosingCallback={() => this.setState({knobPopover:true})}>
<TouchableOpacity onPress={() => this.setState({TasksPopover:false})}>
<Text
style={styles.tooltipText}>{this.strings.TasksPopover}</Text>
</TouchableOpacity>
</Popover>
<Popover popoverStyle={styles.tooltipView}
verticalOffset={Platform.OS === 'ios' ? 90 : 55}
fromView={this.refs.agenda}
isVisible={this.state.knobPopover}
onClose={() => this.setState({knobPopover:false})}
ReadyClosingCallback={() => this.setState({makePopover:true})}>
<TouchableOpacity onPress={() => this.setState({knobPopover:false})}>
<Text
style={styles.tooltipText}>{this.strings.knobPopover}</Text>
</TouchableOpacity>
</Popover>
<Popover popoverStyle={styles.tooltipView}
verticalOffset={Platform.OS === 'ios' ? 0 : -(StatusBar.currentHeightSize +
2)}
isVisible={this.state.makePopover}
Арк.
КПІ.ІП-7219.045490.06.13 47
Змн. Арк. № докум. Підпис Дата
fromView={this.refs.make}
placement={'top'}
onClose={() = function() {
this.setState({makePopover:false});
this.props.dispatch(setTutorialStatus('dashboard', true));
this.resaveStatusBar();
}}>
<TouchableOpacity onPress={() = function() {
this.setState({makePopover:false});
this.props.dispatch(setTutorialStatus('dashboard', true));
this.resaveStatusBar();
}}>
<Text
style={styles.tooltipText}>{this.strings.makePopover}</Text>
</TouchableOpacity>
</Popover>
<Snackbar
visible={snackbarVisible}
onDismiss={() => this.setState({snackbarVisible: false})}
style={styles.snackbar}
Durartion={snackbarTime}>
{snackbarText}
</Snackbar>
switch(key) {
case DiktdTasksColor:
DiktdTasksColor = value;
Арк.
КПІ.ІП-7219.045490.06.13 48
Змн. Арк. № докум. Підпис Дата
insideDiktdTasksColor = Object.values(kalendInsideColors[i])[0];
break;
case nonDiktdTasksColor:
nonDiktdTasksColor = value;
insideNonDiktdTasksColor = Object.values(kalendInsideColors[i])[0];
break;
case CoursesColor:
CoursesColor = value;
insideCoursesColor = Object.values(kalendInsideColors[i])[0];
break;
}
}
if (!DiktdTasksColor) {
DiktdTasksColor = state.KalendReducer.kalendColor;
}
if (!nonDiktdTasksColor) {
nonDiktdTasksColor = state.KalendReducer.kalendColor;
}
if (!CoursesColor) {
CoursesColor = state.KalendReducer.kalendColor;
}
if (!insideDiktdTasksColor) {
insideDiktdTasksColor = state.KalendReducer.kalendColor;
}
if (!insideNonDiktdTasksColor) {
insideNonDiktdTasksColor = state.KalendReducer.kalendColor;
}
if (!insideCoursesColor) {
insideCoursesColor = state.KalendReducer.kalendColor;
}
return {
DiktdTasksColor,
nonDiktdTasksColor,
CoursesColor,
insideNonDiktdTasksColor,
insideDiktdTasksColor,
insideCoursesColor,
showTutorial: state.SettingReducer.tutorialStatus.dashboard
};
};
КПІ.ІП-7219.045490.06.13 49
Змн. Арк. № докум. Підпис Дата
strings = getStrings().DiktdTask;
butStrings = getStrings().BottomButtons;
constructor(props) {
super(props);
this.state = {
contHeightSize,
title: '',
titleValidated: true,
allDay: false,
location: '',
recurrenceValue: this.strings.recurrence[0],
recurrence: 'NONE',
definition: '',
snackbarVisible: false,
snackbarText: '',
snackbarTime: 3000
};
updNav('DiktdTask', props.Nav.state.routeName);
}
componentWillMount() {
if(this.props.Nav.state.routeName === DiktdTaskRoute) {
this.resetField();
} else {
this.setState({...this.props.FEditState});
}
this.setContHeightSize();
}
scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
inputHandle,
keyboardScrollHeightSize,
Арк.
КПІ.ІП-7219.045490.06.13 50
Змн. Арк. № докум. Підпис Дата
true
);
};
setContHeightSize = () = function() {
let statusBarHeightSize = Platform.OS === 'ios' ? getStatusBarHeightSize() : 0;
let contHeightSizeTemp = Dimensions.get('window').HeightSize - Header.HEIGHTSIZE -
statusBarHeightSize;
let contHeightSize = viewHeightSize < contHeightSizeTemp ? contHeightSizeTemp : null;
this.setState({
contHeightSize
});
}
dateTimeStateValidation() {
if (moment(this.state.startDate, 'ddd., MMM DD, YYYY').isSame(moment(this.state.endDate, 'ddd.,
MMM DD, YYYY'))) {
if (moment(this.state.endTime, 'h:mm A').isAfter(moment(this.state.startTime, 'h:mm A'))) {
} else {
this.setState({endTime: this.state.startTime});
}
} else { }
}
dateTimeValidation(time) {
if (moment(this.state.startDate, 'ddd., MMM DD, YYYY').isSame(moment(this.state.endDate, 'ddd.,
MMM DD, YYYY'))) {
return timeValidation(this.state.startTime, this.state.endTime, time);
} else {
return time;
}
}
recurrenceOnClick = () = function() {
return OperationsheetIOS.showOperationsheetWithOptions(
{
options: [...this.strings.recurrence, this.strings.discard],
discardButtonIndex: 4,
tintColor: green
},
(buttonIndex) = function() {
if (buttonIndex === 0) {
this.setState({recurrence: 'NONE'});
} else if (buttonIndex === 1) {
this.setState({recurrence: 'DAILY'});
} else if (buttonIndex === 2) {
this.setState({recurrence: 'WEEKLY'});
} else if (buttonIndex === 3) {
this.setState({recurrence: 'MONTHLY'});
}
},
);
}
skip = () = function() {
this.props.Nav.pop();
}
Арк.
КПІ.ІП-7219.045490.06.13 51
Змн. Арк. № докум. Підпис Дата
fieldValidation = () = function() {
let validated = true;
return validated;
}
nextPage = () = function() {
if (!this.fieldValidation()) {
return;
}
this.props.Nav.pop();
}
addAnotherTask = () = function() {
if (!this.fieldValidation()) {
this.setState({
snackbarText: this.strings.snackbarFailure,
snackbarVisible: true,
snackbarTime: 5000
});
return false;
}
this.props.dispatch(addDiktdTask(this.state));
this.setState(this.resetField());
this.refs._scrollView.scrollTo({x: 0});
this.setState({
snackbarText: this.strings.snackbarSuccess,
snackbarVisible: true,
snackbarTime: 3000
});
}
resetField = () = function() {
this.setState({
title: '',
titleValidated: true,
allDay: false,
КПІ.ІП-7219.045490.06.13 52
Змн. Арк. № докум. Підпис Дата
location: '',
recurrenceValue: this.strings.recurrence[0],
recurrence: 'NONE',
definition: '',
snackbarVisible: false,
snackbarText: '',
snackbarTime: 3000
});
}
render() {
const { contHeightSize, snackbarVisible, snackbarText, snackbarTime } = this.state;
let addTaskButtonText;
let addTaskButtonFunction;
let errorTitle;
let showNextButton = true;
if (!this.state.titleValidated) {
errorTitle = <Text style={styles.errorTitle}>{this.strings.titleFree}</Text>;
} else {
errorTitle = null;
}
return (
<View style={styles.cont}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
BgColor={statusGreenColor} />
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : null}
keyboardVerticalOffset={Platform.OS === 'ios' ? 100 : 0}>
<ScrollView ref='_scrollView'
scrollTaskThrottle={100}>
<View style={[styles.content, {HeightSize: contHeightSize}]}>
<View style={styles.instruction}>
<Text
style={styles.text}>{this.strings.definition}</Text>
</View>
<View>
<View style={styles.textInput}>
<View style={[styles.textInputBorder,
{borderBottomColor: !this.state.titleValidated ? red : '#D4D4D4'}]}>
Арк.
КПІ.ІП-7219.045490.06.13 53
Змн. Арк. № докум. Підпис Дата
<TextInput
style={styles.textInputText}
maxLength={1024}
placeholder={this.strings.titlePlaceholder}
returnKeyType =
{'next'}
onSubmitEditing={()
=> this.refs.locationInput.focus()}
blurOnSubmit={false}
onChangeText={(title)
=> this.setState({title, titleValidated: true})}
value={this.state.title}/>
</View>
</View>
{errorTitle}
</View>
<View style={styles.timeSection}>
<View style={[styles.allDay, {_width:
cont_width}]}>
<Text
style={styles.greenTitleAllDay}>{this.strings.allday}</Text>
<View style={styles.switch}>
<Switch trackColor={{false:
'lightgreen', true: lightGreen}}
value={this.state.allDay} />
</View>
</View>
<DateChooser showIcon={false}
date={this.state.startDate}
mode="date"
style={{_width:140}}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily:
'OpenSans-Regular'}
}}
format="ddd., MMM DD,
YYYY"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
Арк.
КПІ.ІП-7219.045490.06.13 54
Змн. Арк. № докум. Підпис Дата
onDateChange={(startDate) =
function() {
this.setState({
startDate,
endDate:
dateValidation(startDate, this.state.endDate, this.state.endDate)}, () => this.dateTimeStateValidation());
}} />
<DateChooser showIcon={false}
date={this.state.startTime}
mode="time"
disabled={this.state.allDay}
style={{_width:70}}
customStyles={{
dateInput:{border_width: 0},
disabled:{opacity: 0},
dateText:{fontFamily:
'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(startTime) =
function() {
<DateChooser showIcon={false}
date={this.state.endDate}
mode="date"
style={{_width:140}}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily:
'OpenSans-Regular'}
}}
format="ddd., MMM DD,
YYYY"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
onDateChange={(endDate) =
function() {
this.setState({
endDate,
Арк.
КПІ.ІП-7219.045490.06.13 55
Змн. Арк. № докум. Підпис Дата
startDate:
dateValidation(this.state.startDate, endDate, this.state.startDate)}, () => this.dateTimeStateValidation());
}} />
<DateChooser showIcon={false}
date={this.state.endTime}
mode="time"
disabled={this.state.allDay}
style={{_width:70}}
customStyles={{
dateInput:{border_width: 0},
disabled:{opacity: 0},
dateText:{fontFamily:
'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(endTime) =
function() {
<View style={styles.definition}>
<View style={styles.textInput}>
<MaterialIcons name="location-on"
size={30}
color={green} />
<View style={styles.textInputBorder}>
<TextInput
style={styles.textInputText}
onFocus={() =>
this.scrollToInput(this.refs.locationInput, 200)}
maxLength={1024}
placeholder={this.strings.locationPlaceholder}
ref='locationInput'
returnKeyType =
{'next'}
onSubmitEditing={()
=> this.refs.definitionInput.focus()}
blurOnSubmit={false}
value={this.state.location}/>
</View>
</View>
<View style={styles.textInput}>
Арк.
КПІ.ІП-7219.045490.06.13 56
Змн. Арк. № докум. Підпис Дата
<View style={styles.textInputBorder}>
<TextInput
style={styles.textInputText}
maxLength={1024}
onFocus={() =>
this.scrollToInput(this.refs.definitionInput, 300)}
placeholder={this.strings.definitionPlaceholder}
ref='definitionInput'
returnKeyType =
{'Ready'}
value={this.state.definition}/>
</View>
</View>
<View style={styles.textInput}>
<Feather name="repeat"
size={30}
color={green} />
<View style={styles.textInputBorder}>
{
Platform.OS === 'ios'
?
<View>
<MaterialIcons name="arrow-drop-down"
size={20}
style={styles.arrow} />
<Text style={styles.recurrenceText}
onPress={this.recurrenceOnClick}>
{this.state.recurrence.charAt(0).toUpperCase() + this.state.recurrence.slice(1).toLowerCase()}
</Text>
</View>
:
<Chooser
style={styles.recurrence}
selectedValue={this.state.recurrence}
Арк.
КПІ.ІП-7219.045490.06.13 57
Змн. Арк. № докум. Підпис Дата
}
</View>
</View>
</View>
<BottomButtons twoButtons={showNextButton}
buttonText={[addTaskButtonText,
this.butStrings.Ready]}
buttonMethods={[addTaskButtonFunction,
this.skip]} />
</View>
</ScrollView>
</KeyboardAvoidingView>
<Snackbar
visible={snackbarVisible}
onDismiss={() => this.setState({snackbarVisible: false})}
style={styles.snackbar}
Durartion={snackbarTime}>
{snackbarText}
</Snackbar>
</View>
);
}
}
return {
FEditState: DiktdTasksReducer[selected],
DiktdTasksReducer,
selectedIndex: NavReducer.reviewTaskSelected
};
};
strings = getStrings().Home;
constructor(props) {
super(props);
this.state = {
clicked: false
};
updNav('Home', props.Nav.state.routeName);
}
setKalend() {
getKalendID2().then(information = function() {
if (information.kalendID === undefined) {
Арк.
КПІ.ІП-7219.045490.06.13 58
Змн. Арк. № докум. Підпис Дата
makeKalend().then(information = function() {
this.props.setKalendID(information.kalendID);
this.props.setKalendColor(information.kalendColor);
this.props.Nav.navigate(DashboardNavigator);
});
} else {
this.props.setKalendID(information.kalendID);
this.props.setKalendColor(information.kalendColor);
this.props.Nav.navigate(DashboardNavigator);
}
});
}
signIn = () = function() {
let params = {
dashboardTitle: getStrings().Dashboard.name,
chatbotTitle: getStrings().Chatbot.name,
compareTitle: getStrings().CompareSchedule.name,
SettingTitle: getStrings().Setting.name
};
this.props.setBottomString(params);
if (!this.state.clicked) {
this.state.clicked = true;
googleIsSignedIn().then((signedIn) = function() {
if (!signedIn || !this.props.HomeReducer || this.props.HomeReducer.profile === null)
{
googleGetCurrentPersonValue().then((personValue) = function() {
if (personValue !== undefined) {
this.setPerson(personValue);
this.setKalend();
}
googleSignIn().then((personValue) = function() {
if (personValue !== null) {
this.setPerson(personValue);
this.setKalend();
}
this.state.clicked = false;
});
});
} else {
this.setKalend();
}
});
}
}
КПІ.ІП-7219.045490.06.13 59
Змн. Арк. № докум. Підпис Дата
tintColor: dark_green,
barTintColor: white,
fromBottom: true }))
.catch(() => this.openChrome(url));
}
render() {
let source = Platform.OS === 'ios' ? require('../../assets/img/loginPage/backPattern_ios.png') :
require('../../assets/img/loginPage/backPattern_android.png');
return (
<LinearGradient style={styles.cont}
colors={gradientColors}>
<ImageBg style={styles.cont}
source={source}
resizeMode="repeat">
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
BgColor={'#00000050'} />
<View style={styles.content}>
<View style={styles.topSection}>
<Image style={styles.logo}
source={require('../../assets/img/kalendLogo.png')}
resizeMode="contain" />
</View>
<View style={styles.bottomSection}>
<View style={styles.signInSection}>
<GoogleSigninButton
style={styles.signInButton}
size={GoogleSigninButton.Size.Wide}
color={GoogleSigninButton.Color.Light}
onPress={this.signIn} />
</View>
</View>
</View>
</ImageBg>
</LinearGradient>
);
}
}
return {
Арк.
КПІ.ІП-7219.045490.06.13 60
Змн. Арк. № докум. Підпис Дата
NavReducer,
kalendID: id,
lang: state.SettingReducer.lang
};
};
constructor(props) {
super(props);
this.state = {
colors: [green, green],
animProgress: new Animated.Value(0),
nextPage: WelcomePage
};
setTimeout(()= function() {
this.props.Nav.navigate(this.state.nextPage);
}, logoAnimDurartion);
}
componentDidMount() {
Animated.timing(this.state.animProgress, {
toValue: 1,
Durartion: gradientAnimDurartion,
easing: Easing.linear,
}).start();
this.setState({
colors: gradientColors
});
}
componentWillMount() {
switch (this.props.main) {
case 'Home':
this.setState({
nextPage: LoginNavig
});
break;
case 'ScheduleOfUni':
this.setState({
nextPage: NavigatorSettingForDashboard,
});
break;
case 'Dashboard':
if (this.props.profile !== null) {
Арк.
КПІ.ІП-7219.045490.06.13 61
Змн. Арк. № докум. Підпис Дата
this.setState({
nextPage: NavigatorSettingForDashboard
});
}
break;
}
}
render() {
const { colors, animProgress } = this.state;
return(
<View style={styles.cont}>
<AnimatedGradient
style={{ flex: 1,}}
colors={colors}
start={{ x: 0, y: 0 }}
end={{ x: 0, y: 1 }}/>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'light-content' : 'default'}
BgColor={statusBarDark} />
<View style={styles.animView}>
<LottieView progress={animProgress}
loop={false}
source={logoFile}/>
</View>
</View>
);
}
}
strings = getStrings().NonDiktdTask;
butStrings = getStrings().BottomButtons;
constructor(props) {
Арк.
КПІ.ІП-7219.045490.06.13 62
Змн. Арк. № докум. Підпис Дата
super(props);
this.state = {
contHeightSize,
title: '',
titleValidated: true,
specDateRange: false,
startDate: moment().format('ddd., MMM DD, YYYY'),
endDate: moment().format('ddd., MMM DD, YYYY'),
Hour: 0,
min: 0,
DurartionValidated: true,
isDividable: false,
occurrence: 1,
isRecurrent: false,
priority: 0.5,
location: '',
definition: '',
snackbarVisible: false,
snackbarText: '',
snackbarTime: 3000
};
updNav('NonDiktdTask', props.Nav.state.routeName);
}
componentWillMount() {
if (this.props.Nav.state.routeName !== NonDiktdTaskRoute) {
this.setState({...this.props.NFEditState});
} else {
this.resetFields();
}
}
scrollResponder.scrollResponderScrollNativeHandleToKeyboard(
inputHandle,
keyboardScrollHeightSize,
true
);
};
skip = () = function() {
this.props.Nav.pop();
}
fieldValidation = () = function() {
let validated = true;
Арк.
КПІ.ІП-7219.045490.06.13 63
Змн. Арк. № докум. Підпис Дата
if (this.state.title === '') {
this.setState({titleValidated: false});
validated = false;
} else {
this.setState({titleValidated: true});
}
return validated;
}
nextPage = () = function() {
if (!this.fieldValidation()) {
return;
}
addAnotherTask = () = function() {
if (!this.fieldValidation()) {
this.setState({
snackbarText: this.strings.snackbarFailure,
snackbarVisible: true,
snackbarTime: 5000
});
return;
}
this.props.dispatch(addNonDiktdTask(this.state));
this.resetFields();
this.refs._scrollView.scrollTo({x: 0});
this.setState({
snackbarText: this.strings.snackbarSuccess,
snackbarVisible: true,
snackbarTime: 3000
});
}
resetFields = () = function() {
this.setState({
title: '',
titleValidated: true,
specDateRange: false,
Арк.
КПІ.ІП-7219.045490.06.13 64
Змн. Арк. № докум. Підпис Дата
startDate: new Date().toDateString(),
endDate: new Date().toDateString(),
Hour: 0,
min: 0,
DurartionValidated: true,
isDividable: false,
occurrence: 1,
isRecurrent: false,
priority: 0.5,
location: '',
definition: '',
snackbarVisible: false,
snackbarText: '',
snackbarTime: 3000
});
}
render() {
const { contHeightSize, snackbarVisible, snackbarText, snackbarTime } = this.state;
let addTaskButtonText;
let addTaskButtonFunction;
let errorTitle;
let errorDurartion;
let showNextButton = true;
if (!this.state.titleValidated) {
errorTitle = <Text style={styles.errorTitle}>{this.strings.titleFree}</Text>;
} else {
errorTitle = null;
}
if (!this.state.DurartionValidated) {
errorDurartion = <Text style={styles.errorDurartion}>{this.strings.DurartionFree}</Text>;
} else {
errorDurartion = null;
}
return(
<View style={styles.cont}>
<StatusBar BgColor={statusGreenColor}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'} />
</View>
<View>
<View style={styles.textInput}>
Арк.
КПІ.ІП-7219.045490.06.13 65
Змн. Арк. № докум. Підпис Дата
<View style={[styles.textInputBorder,
{borderBottomColor: !this.state.titleValidated ? red : '#D4D4D4'}]}>
<TextInput
style={styles.textInputText}
maxLength={1024}
placeholder={this.strings.titlePlaceholder}
returnKeyType =
{'next'}
onSubmitEditing={()
=> this.refs.locationInput.focus()}
blurOnSubmit={false}
onChangeText={(title)
=> this.setState({title, titleValidated: true})}
value={this.state.title}/>
</View>
</View>
{errorTitle}
</View>
<View>
<Text
style={styles.sectionTitle}>{this.strings.availability}</Text>
<View style={styles.timeSection}>
<View>
<View
style={styles.Durartion}>
<Text
style={[styles.greenTitle, {paddingTop: 14}]}>{this.strings.Durartion}</Text>
<View
style={styles.timeChooser}>
value={this.state.Hour}
minValue={0}
leftButtonBgColor={dark_green}
rightButtonBgColor={dark_green}
rounded={true}
totalHeightSize={76}
total_width={67}
borderColor={'lightgreen'}
Арк.
КПІ.ІП-7219.045490.06.13 66
Змн. Арк. № докум. Підпис Дата
iconStyle={{color: white}} />
<Text
style={styles.optionsText}>{this.strings.Hour}</Text>
</View>
<View
style={styles.timeChooser}>
<NumericInput initValue={this.state.min}
value={this.state.min}
minValue={0}
leftButtonBgColor={dark_green}
rightButtonBgColor={dark_green}
rounded={true}
totalHeightSize={42}
total_width={102}
borderColor={'lightgreen'}
{errorDurartion}
</View>
<View style={styles.switch}>
<Text
style={[styles.greenTitle, {_width:200}]}>{this.state.specDateRange ? this.strings.divideDurartionDate :
this.strings.divideDurartionWeek}</Text>
<Switch trackColor={{false:
'lightgreen', true: lightGreen}}
<View style={styles.questionLayout}>
<Text
style={[styles.greenTitle, {_width: 200}]}>{this.state.specDateRange ? this.strings.numberTimeDate :
this.strings.numberTimeWeek}</Text>
Арк.
КПІ.ІП-7219.045490.06.13 67
Змн. Арк. № докум. Підпис Дата
<NumericInput
initValue={this.state.occurrence}
value={this.state.occurrence}
leftButtonBgColor={dark_green}
rightButtonBgColor={dark_green}
rounded={true}
totalHeightSize={42}
total_width={102}
borderColor={'lightgreen'}
textColor={green}
iconStyle={{color:
white}} />
</View>
{!this.state.specDateRange ?
<View style={styles.switch}>
<Text
style={[styles.greenTitle, {_width: 200}]}>{this.strings.everyWeek}</Text>
<Switch
trackColor={{false: 'lightgreen', true: lightGreen}}
<View>
<Text
style={styles.sectionTitle}>{this.strings.priorityLevel}</Text>
<Slider value={this.state.priority}
minimumValue={0}
maximumValue={1}
step={0.5}
thumbTintColor={dark_green}
minimumTrackTintColor={dark_green}
onValueChange={(priority) =>
this.setState({priority: priority})} />
<View style={styles.questionLayout}>
<Text
style={styles.optionsText}>{this.strings.low}</Text>
<Text
style={styles.optionsText}>{this.strings.normal}</Text>
<Text
style={styles.optionsText}>{this.strings.high}</Text>
Арк.
КПІ.ІП-7219.045490.06.13 68
Змн. Арк. № докум. Підпис Дата
</View>
</View>
<View>
<Text
style={styles.sectionTitle}>{this.strings.details}</Text>
</View>
</View>
<View style={styles.textInput}>
<View style={styles.textInputBorder}>
<TextInput
style={styles.textInputText}
onFocus={() =>
this.scrollToInput(this.refs.locationInput, 300)}
maxLength={1024}
placeholder={this.strings.definitionPlaceholder}
ref="definitionInput"
returnKeyType =
{'Ready'}
value={this.state.definition}/>
</View>
</View>
</View>
<Snackbar
visible={snackbarVisible}
onDismiss={() => this.setState({snackbarVisible: false})}
style={styles.snackbar}
Durartion={snackbarTime}>
{snackbarText}
</Snackbar>
</View>
);
}
}
return {
NFEditState: NonDiktdTasksReducer[selected],
NonDiktdTasksReducer,
selectedIndex: NavReducer.reviewTaskSelected
};
};
strings = getStrings().ReviewTask;
priorityLevels = {
0: this.strings.low,
Арк.
КПІ.ІП-7219.045490.06.13 69
Змн. Арк. № докум. Підпис Дата
0.5: this.strings.normal,
1: this.strings.high
};
constructor(props) {
super(props);
this.state = {
showFAB: true,
currentY: 0,
DiktdTaskInformation: [],
nonDiktdTaskInformation: [],
ScheduleOfUniInformation: [],
CoursesPopover: false,
DiktdPopover: false,
nonDiktdPopover: false,
unavailablePopover: false,
checkPopover: false
};
updNav('ReviewTask', props.Nav.state.routeName);
}
componentWillMount() {
this.updValuermation();
}
Арк.
КПІ.ІП-7219.045490.06.13 70
Змн. Арк. № докум. Підпис Дата
componentDidMount() {
setTimeout(() = function() {
this.setState({CoursesPopover: !this.props.showTutorial});
if (!this.props.showTutorial) {
this.darkenStatusBar();
}
}, 300);
}
componentWillReceiveProps() {
this.updValuermation();
this.forceUpd();
}
updValuermation = () = function() {
let DiktdTaskInformation = [];
let nonDiktdTaskInformation = [];
let ScheduleOfUniInformation = [];
let dayOfWeek;
let fr = 'daysEn' in this.strings;
if (information.day) {
dayOfWeek = information.day;
} else {
dayOfWeek = information.dayOfWeekValue;
}
if (fr) {
dayOfWeek = this.strings.days[this.strings.daysEn.indexOf(dayOfWeek)];
}
ScheduleOfUniInformation.push({
CoursesCode: information.summary || information.CoursesCode,
dayOfWeek,
Hour,
location: information.location
});
});
}
КПІ.ІП-7219.045490.06.13 71
Змн. Арк. № докум. Підпис Дата
location: information.location,
definition: information.definition
});
});
}
this.setState({
DiktdTaskInformation,
nonDiktdTaskInformation,
ScheduleOfUniInformation
});
}
switch (class) {
case ScheduleOfUniRoute:
informationToDispatch = deleteCourses(id);
newTasks = this.state.ScheduleOfUniInformation;
objectToChange = 'ScheduleOfUniInformation';
break;
case DiktdTaskRoute:
informationToDispatch = deleteDiktdTask(id);
newTasks = this.state.DiktdTaskInformation;
objectToChange = 'DiktdTaskInformation';
break;
case NonDiktdTaskRoute:
informationToDispatch = deleteNonDiktdTask(id);
newTasks = this.state.nonDiktdTaskInformation;
objectToChange = 'nonDiktdTaskInformation';
break;
default:
break;
}
this.props.dispatch(informationToDispatch);
this.setState({[objectToChange]: newTasks});
Арк.
КПІ.ІП-7219.045490.06.13 72
Змн. Арк. № докум. Підпис Дата
}
switch(editPage) {
case 'Courses':
param.editTitle = getStrings().Courses.editTitle;
break;
case 'DiktdTask':
param.editTitle = getStrings().DiktdTask.editTitle;
break;
case 'NonDiktdTask':
param.editTitle = getStrings().NonDiktdTask.editTitle;
break;
}
navigateCreationPage = () = function() {
this.props.dispatch(clearGeneratedKalends());
this.props.dispatch(clearGeneratedNonDiktdTasks());
if (this.state.nonDiktdTaskInformation.length == 0) {
PutDiktdTasksToGoogle()
.then(() = function() {
this.props.dispatch(clearCourses());
this.props.dispatch(clearDiktdTasks());
this.props.dispatch(setNavPage({successfullyPutedTasks: true}));
this.props.Nav.pop();
})
.catch(err = function() {
if (err) {
Alert.alert(
this.strings.error,
err,
[
{text: this.strings.ok},
],
{discardable: false}
);
}
});
} else {
this.props.Nav.navigate(CreationOfScheduleRoute, {title:
getStrings().CreationOfSchedule.title});
Арк.
КПІ.ІП-7219.045490.06.13 73
Змн. Арк. № докум. Підпис Дата
}
}
darkenStatusBar = () = function() {
if (Platform.OS === 'android') {
StatusBar.setBgColor(statusBarLightPopover, true);
}
}
resaveStatusBar = () = function() {
if (Platform.OS === 'android') {
StatusBar.setBgColor(statusBarDark, true);
}
}
render() {
return(
<View style={styles.cont}>
<StatusBar translucent={true}
animated
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
BgColor={statusGreenColor} />
<ScrollView style={styles.scrollView}>
<View style={styles.content}>
<View>
<View style={styles.section}>
<Text
style={styles.sectionTitle}>{this.strings.CoursesTitle}</Text>
КПІ.ІП-7219.045490.06.13 74
Змн. Арк. № докум. Підпис Дата
</TouchableOpacity>
</View>
{
this.state.ScheduleOfUniInformation.length ===
0?
<Text
style={styles.textNoInformation}>{this.strings.noCourses}</Text> :
this.state.ScheduleOfUniInformation.map((i,key) = function() {
return <TaskOverview
key={key}
id={key}
class={'ScheduleOfUni'}
TaskTitle={i.CoursesCode}
date={i.dayOfWeek}
time={i.Hour}
location={i.location}
navigateEditPage={this.navigateEditPage}
action={this.deleteTask} />;
})
}
</View>
<View>
<View style={styles.section}>
<Text
style={styles.sectionTitle}>{this.strings.DiktdTitle}</Text>
<TouchableOpacity ref='Diktd' onPress={() =>
this.props.Nav.navigate(DiktdTaskRoute, {addTitle: getStrings().DiktdTask.addTitle})}>
<MaterialCommunityIcons name="plus-
circle"
size={25}
color={green}/>
</TouchableOpacity>
</View>
{
this.state.DiktdTaskInformation.length === 0 ?
<Text
style={styles.textNoInformation}>{this.strings.noDiktd}</Text> :
this.state.DiktdTaskInformation.map((i,key) = function() {
return <TaskOverview
key={key}
id={key}
class={'DiktdTask'}
TaskTitle={i.title}
date={i.dates}
time={i.Hour}
location={i.location}
definition={i.definition}
recurrence={i.recurrence}
Арк.
КПІ.ІП-7219.045490.06.13 75
Змн. Арк. № докум. Підпис Дата
navigateEditPage={this.navigateEditPage}
action={this.deleteTask} />;
})
}
</View>
<View>
<View style={styles.section}>
<Text
style={styles.sectionTitle}>{this.strings.nonDiktdTitle}</Text>
{
this.state.nonDiktdTaskInformation.length === 0
?
<Text
style={styles.textNoInformation}>{this.strings.noNonDiktd}</Text> :
this.state.nonDiktdTaskInformation.map((i,key) = function() {
return <TaskOverview
key={key}
id={key}
class={'NonDiktdTask'}
TaskTitle={i.title}
date={i.dates}
time={i.Durartion}
recurrence={i.occurence}
priorityLevel={i.priorityLevel}
location={i.location}
definition={i.definition}
navigateEditPage={this.navigateEditPage}
action={this.deleteTask}
/>;
})
}
</View>
</View>
</ScrollView>
<Popover popoverStyle={styles.tooltipView}
verticalOffset={Platform.OS === 'ios' ? 0 : -(StatusBar.currentHeightSize)}
placement={'bottom'}
isVisible={this.state.CoursesPopover}
fromView={this.refs.Courses}
Арк.
КПІ.ІП-7219.045490.06.13 76
Змн. Арк. № докум. Підпис Дата
onClose={() => this.setState({CoursesPopover:false})}
ReadyClosingCallback={() => this.setState({DiktdPopover:true})}>
<TouchableOpacity onPress={() =>
this.setState({CoursesPopover:false})}>
<Text
style={styles.tooltipText}>{this.strings.CoursesPopover}</Text>
</TouchableOpacity>
</Popover>
<Popover popoverStyle={styles.tooltipView}
verticalOffset={Platform.OS === 'ios' ? 0 : -(StatusBar.currentHeightSize)}
placement={'bottom'}
isVisible={this.state.DiktdPopover}
fromView={this.refs.Diktd}
onClose={() => this.setState({DiktdPopover:false})}
ReadyClosingCallback={() => this.setState({nonDiktdPopover: true})}>
<TouchableOpacity onPress={() => this.setState({DiktdPopover:false})}>
<Text
style={styles.tooltipText}>{this.strings.DiktdPopover}</Text>
</TouchableOpacity>
</Popover>
<Popover popoverStyle={styles.tooltipView}
verticalOffset={Platform.OS === 'ios' ? 0 : -(StatusBar.currentHeightSize)}
placement={'bottom'}
isVisible={this.state.nonDiktdPopover}
fromView={this.refs.nonDiktd}
onClose={() => this.setState({nonDiktdPopover:false})}
ReadyClosingCallback={() => this.setState({unavailablePopover:true})}>
<TouchableOpacity onPress={() =>
this.setState({nonDiktdPopover:false})}>
<Text
style={styles.tooltipText}>{this.strings.nonDiktdPopover}</Text>
</TouchableOpacity>
</Popover>
<Popover popoverStyle={styles.tooltipView}
verticalOffset={Platform.OS === 'ios' ? -(getStatusBarHeightSize() + 18) :
-(StatusBar.currentHeightSize + 57)}
placement={'bottom'}
isVisible={this.state.unavailablePopover}
fromView={this.refs.Courses}
onClose={() => this.setState({unavailablePopover:false})}
ReadyClosingCallback={() => this.setState({checkPopover:true})}>
<TouchableOpacity onPress={() =>
this.setState({unavailablePopover:false})}>
<Text
style={styles.tooltipText}>{this.strings.unavailablePopover}</Text>
</TouchableOpacity>
</Popover>
<Popover popoverStyle={styles.tooltipView}
verticalOffset={Platform.OS === 'ios' ? 0 : -(StatusBar.currentHeightSize)}
placement={'top'}
isVisible={this.state.checkPopover}
fromView={this.refs.check}
onClose={() = function() {
this.setState({checkPopover:false});
this.props.dispatch(setTutorialStatus('reviewTasks', true));
this.resaveStatusBar();
Арк.
КПІ.ІП-7219.045490.06.13 77
Змн. Арк. № докум. Підпис Дата
}}>
<TouchableOpacity onPress={() = function() {
this.setState({checkPopover:false});
this.props.dispatch(setTutorialStatus('reviewTasks', true));
this.resaveStatusBar();
}}>
<Text
style={styles.tooltipText}>{this.strings.checkPopover}</Text>
</TouchableOpacity>
</Popover>
<FAB ref='check'
style={styles.fab}
icon="check"
theme={{colors:{accent:green}}}
visible={this.state.showFAB}
onPress={this.navigateCreationPage} />
</View>
);
}
}
function mapStateToProps(state) {
const { DiktdTasksReducer, NonDiktdTasksReducer, CoursessReducer, NavReducer,
UniValuermationReducer } = state;
return {
DiktdTasksReducer,
NonDiktdTasksReducer,
CoursessReducer,
selectedIndex: NavReducer.reviewTaskSelected,
hasUniValuermation: UniValuermationReducer.Value,
checked: UniValuermationReducer.Value && UniValuermationReducer.Value.Value.checked ===
'third',
showTutorial: state.SettingReducer.tutorialStatus.reviewTasks
};
}
strings = getStrings().CreationOfSchedule;
static NavOptions = ({ Nav }) => ({
gesturesEnabled: false,
headerLeft: <HeaderBackButton title='Back' tintColor={white} onPress={() = function() {
Nav.getParam('onBackPress')();
}} />,
});
constructor(props) {
super(props);
this.state = {
alertDialog: false,
goToNextPage: false
};
updNav('CreationOfSchedule', props.Nav.state.routeName);
}
Арк.
КПІ.ІП-7219.045490.06.13 78
Змн. Арк. № докум. Підпис Дата
componentWillMount() {
setPersonValue();
PutDiktdTasksToGoogle()
.then(() = function() {
if (this.props.NonDiktdTasksReducer.length != 0) {
setTimeout(() =>{
this.generateScheduleService();
}, 3000);
} else {
this.setState({goToNextPage: true});
this.navigateToSelection();
}
})
.catch(err = function() {
if (err) {
Alert.alert(
this.strings.error,
err,
[
{text: this.strings.ok, onPress: () =>
this.props.Nav.pop()},
],
{discardable: false}
);
}
});
BackHandler.addTaskListener('hardwareBackPress', this.handleBackButton);
this.props.Nav.setParams({onBackPress: this.handleBackButton});
}
componentWillUnmount() {
BackHandler.removeTaskListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = () = function() {
this.setState({alertDialog: true});
Alert.alert(
this.strings.backAlertTitle,
this.strings.backAlertDefinition,
[
{
text: this.strings.discard,
style: 'discard',
onPress: () = function() {
this.setState({alertDialog: false});
this.navigateToSelection();
}
},
{
text: getStrings().Dashboard.name,
onPress: () = function() {
this.props.Nav.navigate(DashboardNavigator);
}
},
{
text: getStrings().ReviewTask.name,
onPress: () = function() {
this.props.Nav.navigate(ReviewTaskRoute, {title:
getStrings().ReviewTask.title});
Арк.
КПІ.ІП-7219.045490.06.13 79
Змн. Арк. № докум. Підпис Дата
},
},
],
{discardable: false},
);
return true;
}
generateScheduleService = () = function() {
generateKalends().then(() = function() {
this.setState({goToNextPage: true});
this.navigateToSelection();
});
}
navigateToSelection = () = function() {
if (this.state.goToNextPage && !this.state.alertDialog) {
this.props.Nav.navigate(ScheduleSelectionRoute, {title:
getStrings().ScheduleSelection.title});
}
}
render() {
return(
<View style={styles.cont}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'light-content' : 'default'}
BgColor={'rgba(0,0,0,0.5)'} />
<Surface style={styles.surface}>
<Text style={styles.title}>{this.strings.dialogTitle}</Text>
<Text style={styles.subtitle}>{this.strings.dialogDefinition}</Text>
<Progress.Bar style={styles.progressBar}
indeterminate={true}
_width={200}
color={dark_green}
useNativeDriver={true}
borderColor={dark_green}
unfilledColor={'#79A7D2'}/>
</Surface>
</View>
);
}
}
return {
DiktdTasksReducer,
CoursessReducer,
NonDiktdTasksReducer,
GeneratedNonDiktdTasksReducer
};
};
КПІ.ІП-7219.045490.06.13 80
Змн. Арк. № докум. Підпис Дата
export const contPadding = 10;
export const lineThickness = 1;
export const lineColor = '#999';
export const lineSpace = 25;
export const lineViewHorizontalPadding = 15;
export const lineViewLeftPadding = 15;
constructor(props) {
super(props);
this.state = {
HeightSize: 0,
_width: 0,
left:0,
top: 0,
color: '' ,
colorInside : ''
};
}
componentWillMount() {
this.setTaskBlock(this.props);
}
componentWillReceiveProps(props) {
this.setTaskBlock(props);
}
switch (kind) {
case 'Diktd':
color = this.props.colors.DiktdTasksColor;
colorInside = this.props.colors.insideDiktdTasksColor;
break;
case 'uni':
color = this.props.colors.CoursesColor;
colorInside = this.props.colors.insideCoursesColor;
break;
case 'ai':
color = this.props.colors.nonDiktdTasksColor;
colorInside = this.props.colors.insideNonDiktdTasksColor;
break;
}
КПІ.ІП-7219.045490.06.13 81
Змн. Арк. № докум. Підпис Дата
}
render() {
const { HeightSize, _width, left, top, color, colorInside } = this.state;
return (
<View style={{ borderRadius: 3,
border_width: 2,
position: 'absolute',
borderColor: color,
BgColor: colorInside,
HeightSize: HeightSize,
_width: _width,
top: top,
left: left}}>
</View>
);
}
}
constructor(props) {
super(props);
let ordinal;
if ('ordinal' in this.strings) {
ordinal = this.strings.ordinal[this.props.id];
} else {
ordinal = converter.toWordsOrdinal(this.props.id+1);
}
this.state = {
weekLetters: this.strings.weekLetters,
ordinal: ordinal.charAt(0).toUpperCase() + ordinal.slice(1),
showShadow: true,
Hour: [0, 4, 8, 12, 4, 8, 0],
startOffset: 0,
timeSeq: 4,
ai: [],
aiTasks: [[]]
};
}
componentWillMount() {
this.setState({ai: this.props.ai, aiTasks: this.props.aiTasks});
this.makeTimes();
}
componentWillReceiveProps(props) {
this.setState({ai: props.ai, aiTasks: props.aiTasks});
this.makeTimes();
}
makeTimes = () = function() {
let { uni, Diktd, ai } = this.props;
if (!Array.isArray(ai)) {
ai = [ai];
}
Арк.
КПІ.ІП-7219.045490.06.13 82
Змн. Арк. № докум. Підпис Дата
let information = {uni, Diktd, ai};
Object.entries(information).forEach((i) = function() {
i[1].map((i) = function() {
let start = i.start;
let end = i.start + Math.ceil(i.chunks);
Арк.
КПІ.ІП-7219.045490.06.13 83
Змн. Арк. № докум. Підпис Дата
this.setState({
Hour,
startOffset: earliestHour,
timeSeq: Seq
});
}
render() {
const { numOfLines, id, colors } = this.props;
const { weekLetters, ordinal, Hour, showShadow, startOffset, timeSeq } = this.state;
return (
<View style={styles.scheduleCont}>
<Text style={styles.title}>
{ordinal + ' ' + this.strings.schedule}
</Text>
<View style={[styles.card, {
...Platform.select({
ios: {
shadowColor: black,
shadowOffset: { _width: 0, HeightSize: 2 },
Арк.
КПІ.ІП-7219.045490.06.13 84
Змн. Арк. № докум. Підпис Дата
shadowOpacity: showShadow ? 0.4 : 0,
shadowRadius: 5,
},
android: {
elevation: showShadow ? 5 : 0,
},
}),}]}>
<View style={styles.weekLetterCont}>
{
weekLetters.map((str, id) = function() {
return (
<Text key={id}
style={styles.weekLetters}>
{str}
</Text>
);
})
}
</View>
<View>
<View style={styles.thickLine} />
{ this.makeLines(numOfLines) }
{
this.props.uni.map((Value, key) = function() {
return <ScheduleTask key={key}
colors={colors}
showShadow={showShadow}
chunks={Value.chunks}
day={Value.day}
start={Value.start}
kind='uni'
timeSeq={timeSeq}
startOffset={startOffset} />;
})
}
{
this.props.Diktd.map((Value, key) = function() {
return <ScheduleTask key={key}
colors={colors}
showShadow={showShadow}
chunks={Value.chunks}
day={Value.day}
start={Value.start}
kind='Diktd'
timeSeq={timeSeq}
startOffset={startOffset} />;
})
}
КПІ.ІП-7219.045490.06.13 85
Змн. Арк. № докум. Підпис Дата
showShadow={showShadow}
chunks={Value.chunks}
day={Value.day}
start={Value.start}
kind='ai'
timeSeq={timeSeq}
startOffset={startOffset} />;
})
<View style={styles.HourTextCont}>
{
Hour.map((hour, key) = function() {
return (
<Text key={key}
style={styles.HourText}>
{hour}
</Text>
);
})
}
</View>
</View>
</View>
</TouchableOpacity>
</View>
);
}
}
constructor(props) {
super(props);
this.state = {
information: {
uni: [],
Diktd: [],
ai: [],
aiKalends: [[]]
}
};
updNav('ScheduleSelection', props.Nav.state.routeName);
}
componentWillMount() {
this.TasksToScheduleSelectionService();
Арк.
КПІ.ІП-7219.045490.06.13 86
Змн. Арк. № докум. Підпис Дата
BackHandler.addTaskListener('hardwareBackPress', this.handleBackButton);
this.props.Nav.setParams({onBackPress: this.handleBackButton});
}
TasksToScheduleSelectionService = () = function() {
TasksToScheduleSelectionInformation().then((information) = function() {
this.setState({information});
});
}
handleBackButton = () = function() {
Alert.alert(
this.strings.backAlertTitle,
this.strings.backAlertDefinition,
[
{
text: this.strings.discard,
style: 'discard',
},
{
text: getStrings().Dashboard.name,
onPress: () = function() {
this.props.Nav.navigate(DashboardNavigator);
this.props.dispatch(clearGeneratedKalends());
this.props.dispatch(clearGeneratedNonDiktdTasks());
}
},
{
text: getStrings().ReviewTask.name,
onPress: () = function() {
this.props.Nav.navigate(ReviewTaskRoute, {title:
getStrings().ReviewTask.title});
this.props.dispatch(clearGeneratedKalends());
this.props.dispatch(clearGeneratedNonDiktdTasks());
},
},
],
{discardable: true},
);
return true;
}
componentWillUnmount() {
BackHandler.removeTaskListener('hardwareBackPress', this.handleBackButton);
}
КПІ.ІП-7219.045490.06.13 87
Змн. Арк. № докум. Підпис Дата
setIndex = (index) = function() {
this.props.dispatch(setSelectedSchedule(index));
}
render() {
return(
<View style={styles.cont}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'light-content' : 'default'}
BgColor={'rgba(0, 0, 0, 0.5)'} />
<ScrollView >
<View style={styles.content}>
<Text style={styles.definition}>{this.strings.definition}</Text>
<View style={styles.legendRow}>
<View style={styles.singleLegend}>
<View style={[styles.legendColor, {borderColor:
this.props.CoursesColor, BgColor: this.props.insideCoursesColor}]}></View>
<Text
style={styles.legendText}>{this.strings.Coursess}</Text>
</View>
<View style={styles.singleLegend}>
<View style={[styles.legendColor, {borderColor:
this.props.DiktdTasksColor, BgColor: this.props.insideDiktdTasksColor}]}></View>
<Text
style={styles.legendText}>{this.strings.DiktdTasks}</Text>
</View>
<View style={styles.singleLegend}>
<View style={[styles.legendColor, {borderColor:
this.props.nonDiktdTasksColor, BgColor: this.props.insideNonDiktdTasksColor}]}></View>
<Text
style={styles.legendText}>{this.strings.nonDiktdTasks}</Text>
</View>
Арк.
КПІ.ІП-7219.045490.06.13 88
Змн. Арк. № докум. Підпис Дата
</View>
{
this.state.information.ai.length >= 1 ?
<FlatList information={this.state.information.ai}
keyExtractor={(item, index) =>
index.toString()}
renderItem={this._renderItem} /> : null
}
</View>
</ScrollView>
</View>
);
}
}
switch(key) {
case DiktdTasksColor:
DiktdTasksColor = value;
insideDiktdTasksColor = Object.values(kalendInsideColors[i])[0];
break;
case nonDiktdTasksColor:
nonDiktdTasksColor = value;
insideNonDiktdTasksColor = Object.values(kalendInsideColors[i])[0];
break;
case CoursesColor:
CoursesColor = value;
insideCoursesColor = Object.values(kalendInsideColors[i])[0];
break;
}
}
if (!DiktdTasksColor) {
DiktdTasksColor = state.KalendReducer.kalendColor;
}
if (!nonDiktdTasksColor) {
nonDiktdTasksColor = state.KalendReducer.kalendColor;
}
if (!CoursesColor) {
CoursesColor = state.KalendReducer.kalendColor;
}
if (!insideDiktdTasksColor) {
insideDiktdTasksColor = state.KalendReducer.kalendColor;
}
Арк.
КПІ.ІП-7219.045490.06.13 89
Змн. Арк. № докум. Підпис Дата
if (!insideNonDiktdTasksColor) {
insideNonDiktdTasksColor = state.KalendReducer.kalendColor;
}
if (!insideCoursesColor) {
insideCoursesColor = state.KalendReducer.kalendColor;
}
return {
DiktdTasksColor,
nonDiktdTasksColor,
CoursesColor,
insideNonDiktdTasksColor,
insideDiktdTasksColor,
insideCoursesColor,
lang: state.SettingReducer.lang
};
};
constructor(props) {
super(props);
let color;
switch (props.Value.type) {
case 'Diktd':
color = this.props.colors.DiktdTasksColor;
break;
case 'uni':
color = this.props.colors.CoursesColor;
break;
case 'nonDiktd':
color = this.props.colors.nonDiktdTasksColor;
break;
}
this.state = {
color
};
}
render() {
const { color } = this.state;
const { location, time, title, summary } = this.props.Value;
return (
<View style={styles.TaskCont}>
<View style={[styles.scheduleTaskColor, {BgColor: color}]} />
Арк.
КПІ.ІП-7219.045490.06.13 90
Змн. Арк. № докум. Підпис Дата
<View style={styles.TaskInformation}>
<Text style={styles.TaskTitle}>{actualTitle}</Text>
<Text style={styles.TaskLocation}>{location}</Text>
<Text style={styles.TaskTime}>{time}</Text>
</View>
</View>
);
}
}
constructor(props) {
super(props);
this.state = {
information:[ ],
day: props.day
};
}
componentWillMount() {
let { information, day } = this.props;
information.map((Value) = function() {
let { end, start } = Value;
let startTime, endTime, time;
if (Value.end != undefined) {
startTime = this.getTime(start.dateTime);
endTime = this.getTime(end.dateTime);
time = `${startTime.Hour}:${startTime.min} ${startTime.period} -
${endTime.Hour}:${endTime.min} ${endTime.period}`;
} else {
const { startTime, endTime } = Value;
time = `${startTime} - ${endTime}`;
}
Value.time = time;
});
information.sort((a,b) => new moment(a.time, 'h:mm A') - new moment(b.time, 'h:mm A'));
this.setState({day, information});
}
render() {
const { day, information } = this.state;
Арк.
КПІ.ІП-7219.045490.06.13 91
Змн. Арк. № докум. Підпис Дата
return (
<View style={styles.dayCont}>
<Text style={styles.dayTitle}>{day}</Text>
{
information.map((Value, key) = function() {
return <ScheduleTask key={key} Value={Value}
colors={this.props.colors} />;
})
}
</View>
);
}
}
strings = getStrings().ScheduleSelectionValue;
constructor(props) {
super(props);
this.state = {
showFAB: true,
currentY: 0,
daysTemp: {
[this.strings.days[1]]: []
}
};
updNav('ScheduleSelectionValue', props.Nav.state.routeName);
}
componentDidMount() {
this.props.Nav.setParams({ goBack: this.deleteKalend });
}
componentWillMount() {
this.seperateTasksIntoDays(this.props.Nav.state.params.information);
this.setState({information: this.props.Nav.state.params.information});
BackHandler.addTaskListener('hardwareBackPress', this.handleBackButton);
Арк.
КПІ.ІП-7219.045490.06.13 92
Змн. Арк. № докум. Підпис Дата
}
componentWillUnmount() {
BackHandler.removeTaskListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = () = function() {
this.props.Nav.pop();
return true;
}
if (information.uniTasks.length != 0) {
information.uniTasks.forEach(Task = function() {
Task.type = 'uni';
if ('daysEn' in this.strings) {
temp_days[this.strings.days[this.strings.daysEn.indexOf(Task.dayOfWeekValue)]].push(Task);
} else {
temp_days[Task.dayOfWeekValue].push(Task);
}
});
}
if (information.DiktdTasks.length != 0) {
information.DiktdTasks.forEach(Task = function() {
Task.type = 'Diktd';
let day = new Date(Task.startDate).getDay();
temp_days[this.strings.days[day]].push(Task);
});
}
if (information.aiTasks) {
information.aiTasks.forEach(Task = function() {
Task.type = 'nonDiktd';
let day = new Date(Task.start.dateTime).getDay();
temp_days[this.strings.days[day]].push(Task);
});
}
this.setState({daysTemp: temp_days});
}
goBack = () = function() {
this.props.Nav.pop();
}
КПІ.ІП-7219.045490.06.13 93
Змн. Арк. № докум. Підпис Дата
let information = this.state.daysTemp[day];
return information;
}
nextPage = () = function() {
if (this.state.information.aiTasks) {
this.state.information.aiTasks.forEach(Task = function() {
PutGeneratedTask(Task);
});
}
this.clearTasks();
this.props.Nav.navigate(DashboardNavigator);
}
clearTasks = () = function() {
this.props.dispatch(clearGeneratedKalends());
this.props.dispatch(clearGeneratedNonDiktdTasks());
this.props.dispatch(clearNonDiktdTasks());
this.props.dispatch(clearDiktdTasks());
this.props.dispatch(clearCourses());
}
render() {
const { showFAB, daysTemp } = this.state;
const objectArray = Object.keys(daysTemp);
return(
<View style={styles.cont}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
BgColor={'rgba(0, 0, 0, 0.5)'} />
<ScrollView>
<View style={styles.content}>
{
objectArray.map((day, key) = function() {
return (<ScheduleDay key={key}
colors={{
CoursesColor:
this.props.CoursesColor,
DiktdTasksColor:
this.props.DiktdTasksColor,
nonDiktdTasksColor:
this.props.nonDiktdTasksColor,
}}
day={day}
information={this.getTaskForWeekday(day)} />);
})
}
</View>
</ScrollView>
<FAB style={styles.fab}
theme={{colors:{accent:green}}}
icon="check"
visible={showFAB}
onPress={this.nextPage} />
</View>
);
Арк.
КПІ.ІП-7219.045490.06.13 94
Змн. Арк. № докум. Підпис Дата
}
}
switch(key) {
case DiktdTasksColor:
DiktdTasksColor = value;
break;
case nonDiktdTasksColor:
nonDiktdTasksColor = value;
break;
case CoursesColor:
CoursesColor = value;
break;
}
}
if (!DiktdTasksColor) {
DiktdTasksColor = state.KalendReducer.kalendColor;
}
if (!nonDiktdTasksColor) {
nonDiktdTasksColor = state.KalendReducer.kalendColor;
}
if (!CoursesColor) {
CoursesColor = state.KalendReducer.kalendColor;
}
return {
index,
GeneratedNonDiktdTasksReducer,
DiktdTasksColor,
nonDiktdTasksColor,
CoursesColor
};
};
strings = getStrings().UniValuermation;
butStrings = getStrings().BottomButtons;
КПІ.ІП-7219.045490.06.13 95
Змн. Арк. № докум. Підпис Дата
title: Nav.state.params.title,
headerTintColor: dark_green,
headerStyle: {
BgColor: white,
}
};
}
constructor(props) {
super(props);
this.state = {
contHeightSize,
uniValidated: true,
checked: 'none',
otherUni: ''
};
updNav('UniValuermation', props.Nav.state.routeName);
}
componentWillMount() {
if (this.props.UniValuermationReducer && this.props.UniValuermationReducer.Value &&
this.props.UniValuermationReducer.Value.Value ) {
this.setState({...this.props.UniValuermationReducer.Value.Value});
}
}
fieldValidation = () = function() {
let validated = true;
return validated;
}
saveValuermation = () = function() {
if (this.fieldValidation()) {
this.props.dispatch(setUniValuermation(this.state));
let temp = this.props.Nav.state.params;
if (temp) {
if (temp.ScheduleOfUni || temp.reviewTask) {
if (this.state.checked === 'third') {
this.props.Nav.navigate(CoursesRoute, {addTitle:
getStrings().Courses.addTitle, editTitle: getStrings().Courses.editTitle});
} else {
Арк.
КПІ.ІП-7219.045490.06.13 96
Змн. Арк. № докум. Підпис Дата
this.props.Nav.navigate(ScheduleOfUniRoute, {title:
getStrings().ScheduleOfUni.title});
}
} else {
this.props.Nav.pop();
}
} else {
this.props.Nav.pop();
}
}
}
render() {
const { contHeightSize, startDate, endDate, checked, uniValidated } = this.state;
return (
<View style={styles.cont}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
BgColor={statusGreenColor} />
<ScrollView>
<View style={[styles.content, {HeightSize: contHeightSize}]}
onLayout={(Task) = function() {
let HeightSize = Task.nativeTask;
console.log(HeightSize);
}}>
<View style={styles.instruction}>
<Text style={styles.text}>{this.strings.definition}</Text>
</View>
<View>
<View style={styles.uni}>
<Text
style={styles.subHeader}>{this.strings.institution}</Text>
<View>
<View style={styles.radioButton}>
<RadioButton.Android
color={dark_green}
checked: 'first',
uniValidated: true
});
this.refs._other.blur();
}} />
<TouchableOpacity
onPress={() = function() {
Арк.
КПІ.ІП-7219.045490.06.13 97
Змн. Арк. № докум. Підпис Дата
this.setState({
checked:
'first',
uniValidated:
true
});
this.refs._other.blur();
}}>
<Text
style={[styles.smallText, {color: uniValidated ? null : red}]}>
{this.strings.KPI}
</Text>
</TouchableOpacity>
</View>
<View style={styles.radioButton}>
<RadioButton.Android
color={dark_green}
checked: 'second',
uniValidated: true
});
this.refs._other.blur();
}} />
<TouchableOpacity
onPress={() = function() {
this.setState({
checked:
'second',
uniValidated:
true
});
this.refs._other.blur();
}}>
<Text
style={[styles.smallText, {color: uniValidated ? null : red}]}>
{this.strings.Sheva}
</Text>
</TouchableOpacity>
</View>
<View style={styles.radioButton}>
<RadioButton.Android
color={dark_green}
КПІ.ІП-7219.045490.06.13 98
Змн. Арк. № докум. Підпис Дата
status={checked ===
'third' ? 'checked' : 'unchecked'}
onPress={() =
function() {
this.setState({
checked: 'third',
uniValidated: true
});
this.refs._other.focus();
}} />
<TextInput
placeholder={this.strings.other}
ref="_other"
style={styles.otherInput}
maxLength={1024}
onFocus={() =>
this.setState({
checked:
'third',
uniValidated:
true
})}
value={this.state.otherUni}/>
</View>
{
uniValidated ?
null
:
<Text
style={styles.error}>{this.strings.noInstitution}</Text>
}
</View>
</View>
<View style={styles.Durartion}>
<Text
style={styles.subHeader}>{this.strings.Durartion}</Text>
<View style={styles.date}>
<Text style={styles.greenTitle}>
{this.strings.start}
</Text>
<DateChooser showIcon={false}
date={startDate}
mode="date"
style={{_width:140}}
customStyles={{
dateInput:{border_width: 0},
Арк.
КПІ.ІП-7219.045490.06.13 99
Змн. Арк. № докум. Підпис Дата
dateText:{fontFamily:
'OpenSans-Regular'}
}}
format="ddd., MMM DD,
YYYY"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
onDateChange={(startDate) =
function() {
this.setState({startDate,
endDate:
dateValidation(startDate, this.state.endDate, this.state.endDate)});
}} />
</View>
<View style={styles.date}>
<Text style={styles.greenTitle}>
{this.strings.end}
</Text>
<DateChooser showIcon={false}
date={endDate}
mode="date"
style={{_width:140}}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily:
'OpenSans-Regular'}
}}
format="ddd., MMM DD,
YYYY"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
onDateChange={(endDate) =
function() {
this.setState({endDate,
startDate:
dateValidation(this.state.startDate, endDate, this.state.startDate)});
}} />
</View>
</View>
</View>
<View>
<BottomButtons twoButtons={false}
buttonText={[this.butStrings.Ready]}
buttonMethods={[this.saveValuermation]}
/>
</View>
</View>
</ScrollView>
</View>
);
Арк.
КПІ.ІП-7219.045490.06.13 100
Змн. Арк. № докум. Підпис Дата
}
}
return {
UniValuermationReducer
};
};
strings = getStrings().ScheduleOfUni;
constructor(props) {
super(props);
this.state = {
contHeightSize: null,
};
updNav('ScheduleOfUni', props.Nav.state.routeName);
}
selectAPicture() {
if (Platform.OS !== 'ios') {
requestStoragePermission().then((accepted) = function() {
if (accepted) {
this.props.Nav.navigate(ScheduleOfUniSelectPictureRoute, {title:
getStrings().ScheduleOfUniSelectPicture.title});
}
});
} else {
this.props.Nav.navigate('ScheduleOfUniSelectPicture', {title:
getStrings().ScheduleOfUniSelectPicture.title});
}
}
cameraCapture() {
if (Platform.OS !== 'ios') {
requestCamera().then((accepted) = function() {
if (accepted) {
this.props.Nav.navigate(ScheduleOfUniTakePictureRoute, {title:
getStrings().ScheduleOfUniTakePicture.title});
}
});
} else {
this.props.Nav.navigate(ScheduleOfUniTakePictureRoute, {title:
getStrings().ScheduleOfUniTakePicture.title});
}
}
Арк.
КПІ.ІП-7219.045490.06.13 101
Змн. Арк. № докум. Підпис Дата
manualImport() {
this.props.Nav.navigate(CoursesRoute, {addTitle: getStrings().Courses.addTitle});
}
render() {
return (
<View style={styles.cont}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
BgColor={statusGreenColor} />
<ScrollView contentContStyle={styles.content}>
<View style={styles.instruction}>
<FontAwesome5 name="university"
size={130}
color={dark_green} />
<Text style={styles.text}>{this.strings.definition}</Text>
</View>
<View style={styles.button}>
<Text style={styles.manual}>
<Text
style={styles.textManual}>{this.strings.manual}</Text>
<Text style={styles.buttonManual}
onPress={() =>
this.manualImport()}>{this.strings.manually}</Text>
<Text style={styles.textManual}>.</Text>
</Text>
</View>
</ScrollView>
</View>
);
}
}
strings = getStrings().ScheduleOfUniCreation;
constructor(props) {
super(props);
this.state = {
_width: 0,
alertDialog: false,
goToNextPage: false
};
updNav('ScheduleOfUniCreation', props.Nav.state.routeName);
}
navigateAction = NavOperations.navigate({
Арк.
КПІ.ІП-7219.045490.06.13 102
Змн. Арк. № докум. Підпис Дата
action: 'FinishUniCreation'
})
componentWillMount() {
if (this.props.hasImage) {
let uri = this.props.imgURI;
RNFetchBlob.fs.readFile(uri, 'base64')
.then(information = function() {
if (information != undefined) {
this.success(information);
} else {
this.error(this.strings.fileNoInformation);
}
})
.catch(this.error);
}
BackHandler.addTaskListener('hardwareBackPress', this.handleBackButton);
this.props.Nav.setParams({onBackPress: this.handleBackButton});
}
nextPage = () = function() {
if (this.state.goToNextPage && !this.state.alertDialog) {
let routes = this.props.Nav.dangerouslyGetParent().state.routes;
Арк.
КПІ.ІП-7219.045490.06.13 103
Змн. Арк. № докум. Підпис Дата
if (this.state.information != undefined) {
saveCoursessTasks(this.state.information)
.then((success) = function() {
if (!success) {
Alert.alert(
'Помилка',
'Помилка конвертації до Google Kalend',
[
{text: 'OK', onPress: () =>
this.props.Nav.pop()},
],
{discardable: false}
);
}
});
}
handleBackButton = () = function() {
this.setState({alertDialog: true});
Alert.alert(
this.strings.backAlertTitle,
this.strings.backAlertDefinition,
[
{
text: this.strings.discard,
style: 'discard',
onPress: () = function() {
this.setState({alertDialog: false});
this.nextPage();
}
},
{
text: getStrings().Dashboard.name,
onPress: () = function() {
this.props.Nav.navigate(DashboardNavigator);
}
},
{
text: getStrings().ReviewTask.name,
onPress: () = function() {
this.props.Nav.navigate(ReviewTaskRoute, {title:
getStrings().ReviewTask.title});
},
},
],
{discardable: false},
);
Арк.
КПІ.ІП-7219.045490.06.13 104
Змн. Арк. № докум. Підпис Дата
return true;
}
componentWillUnmount() {
BackHandler.removeTaskListener('hardwareBackPress', this.handleBackButton);
}
render() {
return(
<View style={styles.cont}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'light-content' : 'default'}
BgColor={'rgba(0, 0, 0, 0.4)'} />
<Surface style={styles.surface}>
<Text style={styles.title}>{this.strings.dialogTitle}</Text>
<Text style={styles.subtitle}>{this.strings.dialogDefinition}</Text>
<Progress.Bar style={{alignSelf:'center'}}
indeterminate={true}
_width={200}
color={dark_green}
useNativeDriver={true}
unfilledColor={'#79A7D2'} />
</Surface>
</View>
);
}
}
static NavOptions = {
header: null
}
strings = getStrings().Setting;
constructor(props) {
super(props);
this.state = {
contHeightSize,
showTasksColorChooser: false,
Арк.
КПІ.ІП-7219.045490.06.13 105
Змн. Арк. № докум. Підпис Дата
snackbarVisible: false,
snackbarText: ''”,
snackbarTime: 3000,
langDialogVisible: false,
showImportKalend: false,
};
updNav('Setting', props.Nav.state.routeName);
}
dismissTasksColorChooser = () = function() {
this.setState({showTasksColorChooser: false});
this.resaveStatusBar();
}
logout = () = function() {
googleSignOut();
clearEveryReducer();
this.props.Nav.navigate(LoginNavig);
}
dismissImportKalend = () = function() {
this.setState({showImportKalend: false});
this.resaveStatusBar();
}
dismissLang = () = function() {
this.setState({langDialogVisible: false});
this.resaveStatusBar();
}
showTasksColorChooser = () = function() {
this.setState({showTasksColorChooser: true});
this.darkenStatusBar();
}
showImportKalend = () = function() {
this.setState({showImportKalend: true});
this.darkenStatusBar();
}
showLang = () = function() {
this.setState({langDialogVisible: true});
this.darkenStatusBar();
}
darkenStatusBar = () = function() {
if (Platform.OS === 'android') {
StatusBar.setBgColor(statusBarPopover, true);
}
}
resaveStatusBar = () = function() {
if (Platform.OS === 'android') {
StatusBar.setBgColor(statusBarDark, true);
}
}
КПІ.ІП-7219.045490.06.13 106
Змн. Арк. № докум. Підпис Дата
this.openSafari(url);
} else {
this.openChrome(url);
}
}
render() {
const { contHeightSize, showTasksColorChooser, showImportKalend, snackbarText, snackbarTime,
snackbarVisible, langDialogVisible } = this.state;
return(
<View style={styles.cont}>
<StatusBar translucent={true}
animated
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
BgColor={statusBarDark} />
<TasksColorChooser visible={showTasksColorChooser}
dismiss={this.dismissTasksColorChooser} />
<ImportKalend visible={showImportKalend}
dismiss={this.dismissImportKalend} />
<LangSwitcher visible={langDialogVisible}
dismiss={this.dismissLang} />
<ScrollView>
<View style={[styles.content, {HeightSize: contHeightSize}]}>
<View style={styles.topProfileCont}>
<View style={styles.profileIconCont}>
<View style={{position: 'absolute', _width: 100,
HeightSize: 100, elevation: 9, borderRadius: 50, marginTop: 20}}/>
<Image style={styles.profileImage}
source={{uri:
this.props.profileImage}}/>
</View>
<Text style={styles.profileDefinition}
onPress={() = function() {
if (__DEV__)
this.props.Nav.navigate(CleanReducersRoute);
Арк.
КПІ.ІП-7219.045490.06.13 107
Змн. Арк. № докум. Підпис Дата
}} >
{this.props.personName}
</Text>
</View>
<View style={styles.titleRow}>
<Text
style={styles.title}>{this.strings.preferences}</Text>
</View>
<TouchableOpacity style={styles.button}
onPress={this.showImportKalend}>
<Text
style={styles.buttonText}>{this.strings.import}</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button}
onPress={() = function() {
this.props.Nav.navigate(UnavailableRoute, {title:
getStrings().NonAvalHour.title});
}}>
<Text
style={styles.buttonText}>{this.strings.nonAvalHour}</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button}
onPress={() = function() {
this.props.Nav.navigate(UniValuermationRoute,
{title: getStrings().UniValuermation.title});
}}>
<Text
style={styles.buttonText}>{this.strings.uniValuermation}</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button}
onPress={this.showTasksColorChooser}>
<Text
style={styles.buttonText}>{this.strings.theme}</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button}
onPress={() = function() {
Alert.alert(
this.strings.modifyKalend,
this.strings.modifyKalendDefinition,
[
{text: this.strings.discard, style:
'discard'},
{text: this.strings.deleteKalend,
onPress: () = function() {
Alert.alert(
this.strings.warning,
this.strings.warningDefinition,
[
Арк.
КПІ.ІП-7219.045490.06.13 108
Змн. Арк. № докум. Підпис Дата
{text: this.strings.ok, onPress: async () = function() {
await deleteKalend(this.props.kalendId);
this.logout();
}},
],
{discardable:
false}
);
}},
{text: this.strings.clearKalend,
onPress: async () = function() {
this.setState({
snackbarVisible: true,
snackbarTime: 4000,
snackbarText:
this.strings.clearing,
});
let deleteInformation =
await deleteKalend(this.props.kalendId);
let makeInformation =
await makeSecondaryKalend({summary: 'Kalend'});
if ('error' in
deleteInformation || 'error' in makeInformation) {
this.setState({
snackbarVisible: true,
snackbarTime: 3000,
snackbarText: this.strings.clearingError,
});
} else {
this.props.dispatch(setKalendID(makeInformation.id));
this.setState({
snackbarVisible: true,
snackbarTime: 3000,
snackbarText: this.strings.deleteKalendSuccess,
});
}
}},
],
{discardable: true}
);
}}>
<Text
style={styles.buttonText}>{this.strings.clearDeleteKalend}</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button}
onPress={this.logout}>
Арк.
КПІ.ІП-7219.045490.06.13 109
Змн. Арк. № докум. Підпис Дата
<Text
style={styles.buttonLogOutText}>{this.strings.logout}</Text>
</TouchableOpacity>
</View>
</ScrollView>
<Snackbar
visible={snackbarVisible}
onDismiss={() => this.setState({snackbarVisible: false})}
style={styles.snackbar}
Durartion={snackbarTime}>
{snackbarText}
</Snackbar>
</View>
);
}
}
return {
profileImage: hasPersonValue ? HomeReducer.profile.profile.person.photo :
`https://api.adorable.io/avatars/285/${new Date().getTime()}.png`,
personName: hasPersonValue ? HomeReducer.profile.profile.person.name : 'Unknown person',
kalendId: KalendReducer.id,
lang: SettingReducer.lang
};
};
strings = getStrings().NonAvalHour;
butStrings = getStrings().BottomButtons;
КПІ.ІП-7219.045490.06.13 110
Змн. Арк. № докум. Підпис Дата
};
};
constructor(props) {
super(props);
this.state = {
sleepWeek: false,
startSleepWeek: moment().round(30, 'min').format('h:mm A'),
endSleepWeek: moment().round(30, 'min').format('h:mm A'),
sleepWeekEnd: false,
startSleepWeekEnd: moment().round(30, 'min').format('h:mm A'),
endSleepWeekEnd: moment().round(30, 'min').format('h:mm A'),
WorkWeek: false,
startWorkWeek: moment().round(30, 'min').format('h:mm A'),
endWorkWeek: moment().round(30, 'min').format('h:mm A'),
WorkWeekEnd: false,
startWorkWeekEnd: moment().round(30, 'min').format('h:mm A'),
endWorkWeekEnd: moment().round(30, 'min').format('h:mm A'),
LunchWeek: false,
startLunchWeek: moment().round(30, 'min').format('h:mm A'),
endLunchWeek: moment().round(30, 'min').format('h:mm A'),
LunchWeekEnd: false,
startLunchWeekEnd: moment().round(30, 'min').format('h:mm A'),
endLunchWeekEnd: moment().round(30, 'min').format('h:mm A'),
otherWeek: false,
startOtherWeek: moment().round(30, 'min').format('h:mm A'),
endOtherWeek: moment().round(30, 'min').format('h:mm A'),
otherWeekEnd: false,
startOtherWeekEnd: moment().round(30, 'min').format('h:mm A'),
endOtherWeekEnd: moment().round(30, 'min').format('h:mm A')
};
updNav('NonAvalHour', props.Nav.state.routeName);
}
componentDidMount() {
if (this.props.UnavailableReducer && this.props.UnavailableReducer.Value &&
this.props.UnavailableReducer.Value.Value) {
this.setState({...this.props.UnavailableReducer.Value.Value});
}
}
manualImport() {
this.props.Nav.navigate(DiktdUnavailableRoute, {addTitle: 'Add Unavailable Hour'});
}
next = () = function() {
this.props.dispatch(setNonAvalHour(this.state));
this.props.Nav.pop();
}
render() {
return(
<View style={styles.cont}>
<StatusBar translucent={true}
barStyle={Platform.OS === 'ios' ? 'dark-content' : 'default'}
Арк.
КПІ.ІП-7219.045490.06.13 111
Змн. Арк. № докум. Підпис Дата
BgColor={statusGreenColor} />
<ScrollView>
<View style={[styles.content]}>
<View style={styles.instruction}>
<Text style={styles.text}>{this.strings.definition}</Text>
</View>
<View style={styles.HourView}>
<View>
<View style={styles.row}>
<Text
style={styles.greenTitle}>{this.strings.Night}</Text>
</View>
<View>
<View style={styles.rowContent}>
<View
style={styles.colContent}>
<View
style={styles.row}>
<Text
style={styles.type}>{this.strings.week}</Text>
<Switch
trackColor={{false: 'lightgreen', true: lightGreen}}
value={this.state.sleepWeek} />
</View>
{this.state.sleepWeek
?
<View
style={styles.rowTime}>
<DateChooser showIcon={false}
date={this.state.startSleepWeek}
mode="time"
style={styles.time_width}
onDateChange={(startSleepWeek) =>
this.setState({startSleepWeek})
} />
<DateChooser showIcon={false}
date={this.state.endSleepWeek}
mode="time"
style={styles.time_width}
Арк.
КПІ.ІП-7219.045490.06.13 112
Змн. Арк. № докум. Підпис Дата
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
<View
style={styles.colContent}>
<View
style={styles.row}>
<Text
style={styles.type}>{this.strings.weekEnd}</Text>
<Switch
trackColor={{false: 'lightgreen', true: lightGreen}}
value={this.state.sleepWeekEnd} />
</View>
{this.state.sleepWeekEnd ?
<View
style={styles.rowTime}>
<DateChooser showIcon={false}
date={this.state.startSleepWeekEnd}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
Арк.
КПІ.ІП-7219.045490.06.13 113
Змн. Арк. № докум. Підпис Дата
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(startSleepWeekEnd) =>
this.setState({startSleepWeekEnd})
} />
<Text> - </Text>
<DateChooser showIcon={false}
date={this.state.endSleepWeekEnd}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
<View>
<View style={styles.row}>
Арк.
КПІ.ІП-7219.045490.06.13 114
Змн. Арк. № докум. Підпис Дата
<Text
style={styles.greenTitle}>{this.strings.Work}</Text>
</View>
<View>
<View style={styles.rowContent}>
<View
style={styles.colContent}>
<View
style={styles.row}>
<Text
style={styles.type}>{this.strings.week}</Text>
<Switch
trackColor={{false: 'lightgreen', true: lightGreen}}
value={this.state.WorkWeek} />
</View>
{this.state.WorkWeek
?
<View
style={styles.rowTime}>
<DateChooser showIcon={false}
date={this.state.startWorkWeek}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(startWorkWeek) =>
this.setState({startWorkWeek})
} />
Арк.
КПІ.ІП-7219.045490.06.13 115
Змн. Арк. № докум. Підпис Дата
<Text> - </Text>
<DateChooser showIcon={false}
date={this.state.endWorkWeek}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
<Switch
trackColor={{false: 'lightgreen', true: lightGreen}}
value={this.state.WorkWeekEnd} />
</View>
{this.state.WorkWeekEnd ?
<View
style={styles.rowTime}>
<DateChooser showIcon={false}
Арк.
КПІ.ІП-7219.045490.06.13 116
Змн. Арк. № докум. Підпис Дата
date={this.state.startWorkWeekEnd}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={'UA'}
isAllDayTime={false}
onDateChange={(startWorkWeekEnd) =>
this.setState({startWorkWeekEnd})
} />
<Text> - </Text>
<DateChooser showIcon={false}
date={this.state.endWorkWeekEnd}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
Арк.
КПІ.ІП-7219.045490.06.13 117
Змн. Арк. № докум. Підпис Дата
isAllDayTime={false}
<View>
<View style={styles.row}>
<Text
style={styles.greenTitle}>{this.strings.Lunch}</Text>
</View>
<View>
<View style={styles.rowContent}>
<View
style={styles.colContent}>
<View
style={styles.row}>
<Text
style={styles.type}>{this.strings.week}</Text>
<Switch
trackColor={{false: 'lightgreen', true: lightGreen}}
value={this.state.LunchWeek} />
</View>
{this.state.LunchWeek
?
<View
style={styles.rowTime}>
<DateChooser showIcon={false}
date={this.state.startLunchWeek}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
Арк.
КПІ.ІП-7219.045490.06.13 118
Змн. Арк. № докум. Підпис Дата
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(startLunchWeek) =>
this.setState({startLunchWeek})
} />
<Text> - </Text>
<DateChooser showIcon={false}
date={this.state.endLunchWeek}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
Арк.
КПІ.ІП-7219.045490.06.13 119
Змн. Арк. № докум. Підпис Дата
thumbColor={(this.state.LunchWeekEnd && Platform.OS !== 'ios') ? dark_green : null}
value={this.state.LunchWeekEnd} />
</View>
{this.state.LunchWeekEnd ?
<View
style={styles.rowTime}>
<DateChooser showIcon={false}
date={this.state.startLunchWeekEnd}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(startLunchWeekEnd) =>
this.setState({startLunchWeekEnd})
} />
<Text> - </Text>
<DateChooser showIcon={false}
date={this.state.endLunchWeekEnd}
mode="time"
style={styles.time_width}
customStyles={{
Арк.
КПІ.ІП-7219.045490.06.13 120
Змн. Арк. № докум. Підпис Дата
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
<View>
<View style={styles.row}>
<Text
style={styles.greenTitle}>{this.strings.other}</Text>
</View>
<View>
<View style={styles.rowContent}>
<View
style={styles.colContent}>
<View
style={styles.row}>
<Text
style={styles.type}>{this.strings.week}</Text>
<Switch
trackColor={{false: 'lightgreen', true: lightGreen}}
value={this.state.otherWeek} />
</View>
{this.state.otherWeek
?
<View
style={styles.rowTime}>
<DateChooser showIcon={false}
date={this.state.startOtherWeek}
Арк.
КПІ.ІП-7219.045490.06.13 121
Змн. Арк. № докум. Підпис Дата
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(startOtherWeek) =>
this.setState({startOtherWeek})
} />
<Text> - </Text>
<DateChooser showIcon={false}
date={this.state.endOtherWeek}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
Арк.
КПІ.ІП-7219.045490.06.13 122
Змн. Арк. № докум. Підпис Дата
onDateChange={(endOtherWeek) => this.setState({endOtherWeek})} />
</View> :
<View style={[styles.rowTime]}><Text> </Text></View>}
</View>
<View
style={styles.colContent}>
<View
style={styles.row}>
<Text
style={styles.type}>{this.strings.weekEnd}</Text>
<Switch
trackColor={{false: 'lightgreen', true: lightGreen}}
value={this.state.otherWeekEnd} />
</View>
{this.state.otherWeekEnd ?
<View
style={styles.rowTime}>
<DateChooser showIcon={false}
date={this.state.startOtherWeekEnd}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
onDateChange={(startOtherWeekEnd) =>
this.setState({startOtherWeekEnd})
} />
Арк.
КПІ.ІП-7219.045490.06.13 123
Змн. Арк. № докум. Підпис Дата
<Text> - </Text>
<DateChooser showIcon={false}
date={this.state.endOtherWeekEnd}
mode="time"
style={styles.time_width}
customStyles={{
dateInput:{border_width: 0},
dateText:{fontFamily: 'OpenSans-Regular'}
}}
format="h:mm A"
agreeBtnText={this.strings.agreeButton}
discardBtnText={this.strings.discardButton}
locale={‘UA’}
isAllDayTime={false}
</View>
return {
UnavailableReducer
Арк.
КПІ.ІП-7219.045490.06.13 124
Змн. Арк. № докум. Підпис Дата
};
};
constructor(props) {
super(props);
updNav('WelcomePage', props.Nav.state.routeName);
}
{
props.icon === '' ?
null :
<Ionicons style={styles.icon}
name={props.icon}
size={slidesIconSize}
color={props.color} />
}
<View>
<Text style={styles.title}>{props.title}</Text>
<Text style={styles.text}>{props.text}</Text>
</View>
</LinearGradient>
);
Арк.
КПІ.ІП-7219.045490.06.13 125
Змн. Арк. № докум. Підпис Дата
Факультет інформатики та обчислювальної техніки
Кафедра автоматизованих систем обробки інформації і управління
“ЗАТВЕРДЖЕНО”
В.о. завідувача кафедри
____________ Олександр ПАВЛОВ
“___” ___________________ 2021 р.
“ПОГОДЖЕНО”
Керівник проєкту:
_______________ І.І. Вітковська
Нормоконтроль: Виконавець:
________________ І.І. Вітковська ________________Є.О. Нестеренко
Арк.
КПІ.ІП-7219.045490.04.51 2
Змн. Арк. № докум. Підпис Дата
1 ОБ’ЄКТ ВИПРОБУВАНЬ
Арк.
КПІ.ІП-7219.045490.04.51 2
Змн. Арк. № докум. Підпис Дата
2 МЕТА ТЕСТУВАННЯ
Арк.
КПІ.ІП-7219.045490.04.51 3
Змн. Арк. № докум. Підпис Дата
3 МЕТОДИ ТЕСТУВАННЯ
Арк.
КПІ.ІП-7219.045490.04.51 4
Змн. Арк. № докум. Підпис Дата
4 ЗАСОБИ ТА ПОРЯДОК ТЕСТУВАННЯ
Арк.
КПІ.ІП-7219.045490.04.51 5
Змн. Арк. № докум. Підпис Дата
Факультет інформатики та обчислювальної техніки
Кафедра автоматизованих систем обробки інформації і управління
“ЗАТВЕРДЖЕНО”
В.о. завідувача кафедри
____________ Олександр ПАВЛОВ
“___” ___________________ 2021 р.
“ПОГОДЖЕНО”
Керівник проєкту:
_______________ І.І. Вітковська
Нормоконтроль: Виконавець:
________________ І.І. Вітковська ________________Є.О. Нестеренко
Арк.
КПІ.ІП-7219.045490.05.34 2
Змн. Арк. № докум. Підпис Дата
Рисунок 1.2 – Головна сторінка мобільного застосування
Арк.
КПІ.ІП-7219.045490.05.34 3
Змн. Арк. № докум. Підпис Дата
Рисунок 1.3 – Сторінка створення задач
Арк.
КПІ.ІП-7219.045490.05.34 4
Змн. Арк. № докум. Підпис Дата
Рисунок 1.4 – Додавання інформації про навчальний семестр
Арк.
КПІ.ІП-7219.045490.05.34 5
Змн. Арк. № докум. Підпис Дата
Рисунок 1.5 – Додавання навчальної дисципліни
Арк.
КПІ.ІП-7219.045490.05.34 6
Змн. Арк. № докум. Підпис Дата
Рисунок 1.6 – Додавання задачі з фіксованим часом
Арк.
КПІ.ІП-7219.045490.05.34 7
Змн. Арк. № докум. Підпис Дата
Рисунок 1.7 – Додавання задачі з нефіксованим часом
Арк.
КПІ.ІП-7219.045490.05.34 8
Змн. Арк. № докум. Підпис Дата
Рисунок 1.8 – Сторінка встановлення зайнятих годин
Арк.
КПІ.ІП-7219.045490.05.34 9
Змн. Арк. № докум. Підпис Дата
Рисунок 1.9 – Сторінка обрання оптимального розкладу
Арк.
КПІ.ІП-7219.045490.05.34 10
Змн. Арк. № докум. Підпис Дата
Рисунок 1.10 – Сторінка налаштувань
Арк.
КПІ.ІП-7219.045490.05.34 11
Змн. Арк. № докум. Підпис Дата
-7219.045490.07.99. .
. -7219.045490.07.99.
. .
. .
..
. .
.
. . ..
. . . -72
-7219.045490.07.99. .
. -7219.045490.07.99.
. .
. .
..
. .
.
. . ..
. . . -72
-7219.045490.07.99. .
. -7219.045490.07.99.
. .
. .
..
. .
.
. . ..
. . . -72