You are on page 1of 37

INTERNSHIP PROJECT REPORT

(Project Term July-January, 2018)

INTERN as iOS Developer

Submitted by

Ajay Negi Registration Number: 11506554

Course Code: CSE441

Under the Guidance of

Mr. Aseem Kumar

School of Computer Science and Engineering

1
Page
DECLARATION

I hereby declare that the internship project report is an authentic record of my own work
carried out as requirements of internship report submission for the award of B.Tech degree
in Computer Science Engineering from Lovely Professional University, Phagwara, under the
guidance of Mr. Sami Anand, during July to January 2018. All the information furnished in
this internship project report is based on my own intensive work and is genuine.

Name of Student: Ajay Negi


Registration Number: 11506554

(Signature of Student )
Date: 05-25-2019

2
Page
CERTIFICATE

This is to certify that the declaration statement made by the student is correct to the best of
my knowledge and belief. He has completed this Internship Project Report under my
guidance and supervision. The present work is the result of their original investigation, effort
and study. No part of the work has ever been submitted for any other degree at any
University. The Internship Project Report is fit for the submission and partial fulfillment of
the conditions for the award of B.Tech degree in Computer Science Engineering from
Lovely Professional University, Phagwara.

Signature and Name of the Mentor :

Designation :

School of Computer Science and Engineering,


Lovely Professional University,
Phagwara, Punjab.

Date:

3
Page
Page
4
ACKNOWLEDGEMENT

I am thankful to my manager and mentor Mr. Aseem Kumar for providing me this
opportunity to work upon the projects and enhance my learning. I am also thankful to
my other colleagues for providing me support and guidance throughout my work.
I specially thanks Click Labs for providing me this wonderful opportunity to work with
the team as an intern and have wonderful learning experience.

5
Page
CONTENTS

1. Introduction
2. Problem Statement
3. Existing System
• Introduction
• Existing Software
• DFD for present system
• What’s new in the system to be developed
4. Problem Analysis
• Product definition
• Feasibility Analysis
• Project Plan
5. Software Requirement Analysis
• Introduction
• General Description
• Specific Requirements
6. Design
• System Design
• High level Design
• Low level design
• Codes/Screenshot
7. Testing
• Functional testing
• Structural testing
• Levels of testing
• Testing the project
8. Implementation
• Implementation of the project
• Conversion Plan
• Post Implementation
9. Project Legacy
6
Page

10. References
1. INTRODUCTION

I am working as an intern in Click Labs (JUGNOO) in the team Project


Development under the guidance and mentorship of Mr. Hardeep Singh. My
role is to debug and develop iOS application and enhance the functionalities,
by adding new or fixing existing features in the product. I worked on the
product WorkFlow of the company to fix some bugs and to add some
features into the product.

I worked on designing and building of the product called Tookan


(Tracking Software). Which has been built under company’s jungleworks
team.

7
Page
2. PROBLEM STATEMENTS

● Related to WorkFlow

○ Story: Add local notification when some user is going on leave or if


he or she taking some break in between their work...
○ Show the Notification after the time which is entered by user itself,
work as a reminder and also had to do white labelling according to
the customer need.
○ Some Bugs:
○ Data stored was int type that is time but we have to fetch in
date format.
○ Problem in getting data from core data.
○ User Notification works on particular time
○ Remote Notification was not working from back end.
○ Core Data was crowded too much
○ Excessive use of Prototype Cell

3. EXISTING SYSTEM

● INTRODUCTION

Workflow app basically keep track of all the employee in an organisation , flow
of an app start from log in and sign up which receive token from API, after that
it jumps into main page where we can add our daily work routine also on which
particular task we have been working, Workflow also works as remainder for
user which allow them to remind their activity (which was my task in team to
achieve).
8
Page
● EXISTING PRODUCTS

1. XCode 11
It is a platform provided by apple which allow us to build application
for iOS. It comes with many frame work which make user to write less
code and interact more with their work
Features:
1. Card View, Map View
2. Core Data
3. Table View, Collection View
4. Widgets (slider, switch, label. Text field)
5. Notifications
2. Core Data
It is a framework of a XCode, this is own data base of the XCode, it also
saves data in the form of table and we can fetch or save data accordingly,
it is a complete copy of SQL and work as same also.

3. Swift 4
Swift is a high-level programming language developed by Apple and
made available in 2014. It is designed for writing apps for Apple
platforms, including macOS, iOS, tvOS, and watchOS
1. Object Oriented
2. Type Safe

4. REST API
Representational State Transfer (REST) is a software style that
defines a set of constraints to be used for creating web services. Web
services that conform to the REST architectural style,
called RESTful Web services (RWS), provide interoperability
between computer systems on the internet. RESTful Web services
allow the requesting systems to access and manipulate textual
representations of web resources by using a uniform and predefined
set of stateless operations. Other kinds of Web services, such a
SOAP Web services, expose their own arbitrary sets of operations
9
Page
● DATA FLOW DIAGRAM

The process to complete the Story, Project task or Feature.

10
Page
~ Process cycle to solve the Bug

● NEW DEVELOPMENT

New release of software is done with fixed bugs, crashes and added feature. As,
the bugs and crashes are fixed, it goes for testing to the QA team. As the code
passes all the tests by QA, finally the release goes for the deployment of new
version to live production for use.

11
Page
4. PROBLEM ANALYSIS

● INTRODUCTION
Adding new features or fixing the bugs is the most important part of a developer.
Most of the time is spent to enhance the performance of the project to make it
work better with the increase amount of customer’s suggestions and
requirements received by the company. Analyzing the requirements of clients
and the need to upgrade, are the two most important factors, which must be
taken into consideration for the releases of new version of products.
1. Add Reminder Show Notification as per data entered or value
set by the user.
2. Managing white labelling in a application.
3. Creating queries and new entity for values stored by user.
4. User Notification Framework
5. Data fetch must be of Date type.

● FEASIBILITY ANALYSIS

The need to resolve an issue, it is much necessary to realize which task i.e. to
select task from the assigned issues, to be worked upon. Thus, the priorities are
set for each task, which helps in scheduling the systematic work process. These
priorities are either set by the QA team or by the client itself, and accordingly
the developer’s team work upon them, giving preference to high priority tasks.

Layout Constraints and Maintenance:


The task is to set local notification according to values selected by the user
from picker. To fetch it from Core Data, but main thing is to keep in mind
while developing app is auto layout, so it can free work on every apple device.
● Make Customer to use app without any bug and must enjoy app flow.
12
Page
■ Add count of Messages, Notes, Activity on the task Information
that had happened or will happen.
A database query is written to fetch the count of data types and then they
are shown into header at proper ui widget.
■ Hide show more button if No Custom fields are there.
Added a method to ask localState if there is custom field for this queue in
which Value is there. If it returned true then set Notification.

Push Notification:
■ To show the notification also from backend side, which is really a
big task but can be achieved by getting certificates.
There was an API already to send the notifications I used the that API to
send the notification to agent.

Date picker should be only user by toolbar (Bug)


■ Used of toolbar to store minutes in core data if not toolbar is used it
won’t show done and while editing text field, we can’t save value
inside a table.

Media must work when notification pop out (Bug).


■ Batch content body and sounds these are four major part of the user
notification but working in simulator it would be hard to produce by
default ringtone so we had to put some external sounds.
■ Also, when media is deleted, bundle must produce by default
sound.

Error handling if some issue arrived (Bug).


■ Sometimes there is token problem, unwrapping problem and index
array out of bound error also arrived we had to use guard statement
and had to keep every statement under if let statement so at least
when some error is arriving it can be handled. 13
Page
How to fetch chosen value from core data. (Bug)
■ There are many values that has been stored in core data how we
decide that which particular value is our there are following two
ways
■ 1.must fetch last two updated value as count-1 and count-2
■ 2.must fetch value according to the time it has been set.

Conversion of string and into date (Bug).


■ Type casting is always as issue in any language there are many
different types of value under this project so we have to make them
similar so they can all work as same.

● PROJECT PLAN

Every two week developers and project managers have a meeting to decide the
workflow for the next sprint (tanure of two week constitutes a sprint). In the
meeting, the bugs and requirement of new feature or functionality, are decided
and a roadmap is planned to execute these fixes.

Beside this, before the release of version, a meeting is held between the QA,
developers and product management team to check whether the changes and
fixes are best to go with the release date, without effecting other data or
products.

Basically, other projects can go on release on any of the date of month. But our
project has a major concern, as it causes a downtime, so it usually goes on
release for weekends.
14
Page
5. SOFTWARE REQUIREMENT ANALYSIS

1. Employee Training manager

● INTRODUCTION

Employee Training manager is a project which is given to us for designing and


developing. Its objective is to create a solution for the company to manage the
work flow for the employees. Their task specially

○ Specific Requirements

i. Admin can add Employees and can create team.


i. Admin can assign Team Lead to respective team.
iii. HR can enroll Employee for Training.
iv. Team lead can create a training.
v. Team lead can create a training plan (series of training).
vi. Team lead can assign a particular training plan to a particular employee.
Vii. Team lead can track progress of each training in the training plan for a
particular employee.
Viii. Employee can update status of training.

6. DESIGN

1. High Level Design:


Users: There are 4 types of users:
1.Employee - who is currently undergoing training.
2.Team Lead - who can create and assign training.
3.HR - To create employee id of employee while onboarding.

Services:
1) Training Plan Service:
This service will be responsible for managing,creating,deleting features related to Training
Plan and also Templates. The service's accessablity and CRUD privilege is limited to
only Team Lead user Type.

2) Training Template Service:


This service will be responsible for managing the resources of a Training in a Template
Plan. This service is accessible to Team Lead only.
15

Database / Data Structure:


Page
1. store details of each Training (id, name, start date,end date,Assignment
start date,Assignment end date, Mentor Name).
2. store information related to Training Plan (id , name, List of Employees taking
this training).
3 store all users registered to the application (User id,user name, User type).
4. store list of all employees with their assigned Training (employee id , List of Trainings)
5. store all Templates (List of trainings).

2. Interfaces:

User Hierarchy Chart, above shows how appropriate user will be created by assigning
appropriate user types to all user. So that they can advantage of already built-in Roles.

This diagram shows flow and tasks that a team leader can perform in our service.
16
Page
UI Mockups:

This is the mock representation of Dashboard of team lead. Which how team would be able
to create training plan or View the Progress of the employee.

3. Low Level Design:

Data Store:
import UIKit
import UserNotifications

enum NotificationSettingsSections: Int, CaseIterable {


case NotificationEnabled
case ShiftNotifications
case BreakNotifications
case TaskNotifications
init(id: Int) {
switch id {
case 0:
self = .NotificationEnabled
case 1:
self = .ShiftNotifications
case 2:
self = .BreakNotifications
default:
17

self = .TaskNotifications
}
Page

}
}

enum NotificationTime: Int, CaseIterable {


case notificationType, notificationTime
init(index: Int) {
switch index {
case 0:
self = .notificationType
default:
self = .notificationTime
}
}
}

class NotificationSettingsViewController: UIViewController {

// MARK :- Variables
let notificationCenter = UNUserNotificationCenter.current()

// MARK :- IBOutlets
@IBOutlet weak var notificationSettingsTableView: UITableView!

// MARK :- View life cycles


override func viewDidLoad() {
super.viewDidLoad()

nibRegister()
notificationSettingsTableView.allowsSelection = false
self.title = "Notification"
}

override func viewWillAppear(_ animated: Bool) {


super.viewWillAppear(animated)
checkNotificationAuthorizationStatus()
NotificationManager.notificationManager.updateNotificationSetting()
}

// MARK :- Private functions


private func checkNotificationAuthorizationStatus() {
notificationCenter.getNotificationSettings { (settings) in
if settings.authorizationStatus != .authorized {
self.showAlert("Please, turn notification on from setting!!!")
}
}
}

private func nibRegister() {


18

notificationSettingsTableView.register(UINib(nibName: "NotificationsEnabledCell",
Page

bundle: nil), forCellReuseIdentifier: "NotificationsEnabledCell")


notificationSettingsTableView.register(UINib(nibName:
"NotificationTimeTableViewCell", bundle: nil), forCellReuseIdentifier:
"NotificationTimeTableViewCell")
}

// MARK :- Actions on switch state


@objc private func notificationsEnabledStateChanged(switchState: UISwitch) {
if switchState.isOn == true {
switchState.setOn(true, animated: true)
UserDefaults.standard.set(switchState.isOn, forKey:
UserDefaultsKey.notificationState)
} else {
switchState.setOn(false, animated: true)
UserDefaults.standard.set(switchState.isOn, forKey:
UserDefaultsKey.notificationState)
}
notificationSettingsTableView.reloadData()
NotificationManager.notificationManager.updateNotificationSetting()
}

@objc private func shiftNotificationsEnabledStateChanged(switchState: UISwitch) {


if switchState.isOn == true {
switchState.setOn(true, animated: true)
UserDefaults.standard.set(switchState.isOn, forKey: UserDefaultsKey.shiftState)
} else {
switchState.setOn(false, animated: true)
UserDefaults.standard.set(switchState.isOn, forKey: UserDefaultsKey.shiftState)
}
notificationSettingsTableView.reloadData()
NotificationManager.notificationManager.updateNotificationSetting()
}

@objc private func breakNotificationsEnabledStateChanged(switchState: UISwitch) {


if switchState.isOn == true {
UserDefaults.standard.set(switchState.isOn, forKey: UserDefaultsKey.breakState)
switchState.setOn(true, animated: true)
} else {
UserDefaults.standard.set(switchState.isOn, forKey: UserDefaultsKey.breakState)
switchState.setOn(false, animated: true)
}
notificationSettingsTableView.reloadData()
NotificationManager.notificationManager.updateNotificationSetting()
}

@objc private func taskNotificationsEnabledStateChanged(switchState: UISwitch) {


if switchState.isOn == true {
UserDefaults.standard.set(switchState.isOn, forKey: UserDefaultsKey.taskState)
switchState.setOn(true, animated: true)
19

} else {
Page

UserDefaults.standard.set(switchState.isOn, forKey: UserDefaultsKey.taskState)


switchState.setOn(false, animated: true)
}
notificationSettingsTableView.reloadData()
NotificationManager.notificationManager.updateNotificationSetting()
}
}

extension NotificationSettingsViewController: UITableViewDelegate,


UITableViewDataSource {

// MARK :- Table view delegate and dataSource


func numberOfSections(in tableView: UITableView) -> Int {
return NotificationSettingsSections.allCases.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {


switch NotificationSettingsSections(id: section) {
case .NotificationEnabled:
return 1
case .ShiftNotifications:
if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == false {
return NotificationTime.allCases.count - 1
} else {
if UserDefaults.standard.bool(forKey: UserDefaultsKey.shiftState) == false {
return NotificationTime.allCases.count - 1
} else {
return NotificationTime.allCases.count
}
}
case .BreakNotifications:
if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == false {
return NotificationTime.allCases.count - 1
} else {
if UserDefaults.standard.bool(forKey: UserDefaultsKey.breakState) == false {
return NotificationTime.allCases.count - 1
} else {
return NotificationTime.allCases.count
}
}
default:
if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == false {
return NotificationTime.allCases.count - 1
} else {
if UserDefaults.standard.bool(forKey: UserDefaultsKey.taskState) == false {
return NotificationTime.allCases.count - 1
} else {
return NotificationTime.allCases.count
}
20

}
Page

}
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) ->


String? {
switch NotificationSettingsSections(id: section) {
case .NotificationEnabled:
return "Notification enabled"
case .ShiftNotifications:
return "Shift notification enabled"
case .BreakNotifications:
return "Break notification enabled"
case .TaskNotifications:
return "Task notification enabled"
}
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->


UITableViewCell {
switch NotificationSettingsSections(id: indexPath.section) {
case .NotificationEnabled:
guard let cell = tableView.dequeueReusableCell(withIdentifier:
"NotificationsEnabledCell") as? NotificationsEnabledCell else {
fatalError("Cell Initialization failed")
}
checkNotificationAuthorizationStatus()
cell.notificationEnabledLabel.text = "Show Notifications"
cell.notificationEnabledSwitch.setOn(UserDefaults.standard.bool(forKey:
UserDefaultsKey.notificationState), animated: true)
cell.notificationEnabledSwitch.addTarget(self, action:
#selector(notificationsEnabledStateChanged(switchState:)), for: .valueChanged)
return cell

case .ShiftNotifications:
switch NotificationTime(index: indexPath.row) {
case .notificationType:
guard let cell = tableView.dequeueReusableCell(withIdentifier:
"NotificationsEnabledCell") as? NotificationsEnabledCell else {
fatalError("Cell Initialization failed")
}
cell.notificationEnabledSwitch.addTarget(self, action:
#selector(shiftNotificationsEnabledStateChanged(switchState:)), for: .valueChanged)
cell.notificationEnabledLabel.text = "Shift Notification"
if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == false
{
cell.notificationEnabledSwitch.setOn(false, animated: true)
} else {
cell.notificationEnabledSwitch.setOn(UserDefaults.standard.bool(forKey:
UserDefaultsKey.shiftState), animated: true)
21

}
Page

return cell
case .notificationTime:
guard let cell = tableView.dequeueReusableCell(withIdentifier:
"NotificationTimeTableViewCell") as? NotificationTimeTableViewCell else {
fatalError("Cell Initialization failed")
}
cell.notificationStartTimeLabel.text = "Shift notification start before"
cell.notificationEndTimeLabel.text = "Shift notification end before"
if UserDefaults.standard.string(forKey: UserDefaultsKey.shiftStart) == nil {
UserDefaults.standard.set("01", forKey: UserDefaultsKey.shiftStart)
UserDefaults.standard.set("01", forKey: UserDefaultsKey.shiftEnd)
}
cell.startTimeTextField.text = UserDefaults.standard.string(forKey:
UserDefaultsKey.shiftStart)! + " min"
cell.endTimeTextField.text = UserDefaults.standard.string(forKey:
UserDefaultsKey.shiftEnd)! + " min"
cell.startTimeTextField.tag = indexPath.section
cell.endTimeTextField.tag = indexPath.section
cell.timePickerDelegate = self

cell.startIndex = cell.timeList.index(of: UserDefaults.standard.string(forKey:


UserDefaultsKey.shiftStart) ?? "01") ?? 0
cell.startPickerView?.selectRow(cell.startIndex, inComponent: 0, animated: true)
cell.endIndex = cell.timeList.index(of: UserDefaults.standard.string(forKey:
UserDefaultsKey.shiftEnd) ?? "01") ?? 0
cell.endPickerView?.selectRow(cell.endIndex, inComponent: 0, animated: true)
cell.startString = UserDefaults.standard.string(forKey:
"shiftStartNotificationTime")
cell.endString = UserDefaults.standard.string(forKey: UserDefaultsKey.shiftEnd)

if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == false


{
cell.isHidden = true
} else {
if UserDefaults.standard.bool(forKey: UserDefaultsKey.shiftState) == false {
cell.isHidden = true
} else {
cell.isHidden = false
}
}
return cell
}

case .BreakNotifications:
switch NotificationTime(index: indexPath.row) {
case .notificationType:
guard let cell = tableView.dequeueReusableCell(withIdentifier:
"NotificationsEnabledCell") as? NotificationsEnabledCell else {
fatalError("Cell Initialization failed")
22

}
Page
cell.notificationEnabledSwitch.addTarget(self, action:
#selector(breakNotificationsEnabledStateChanged(switchState:)), for: .valueChanged)
cell.notificationEnabledLabel.text = "Break Notification"
if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == false
{
cell.notificationEnabledSwitch.setOn(false, animated: true)
} else {
cell.notificationEnabledSwitch.setOn(UserDefaults.standard.bool(forKey:
UserDefaultsKey.breakState), animated: true)
}
return cell
case .notificationTime:
guard let cell = tableView.dequeueReusableCell(withIdentifier:
"NotificationTimeTableViewCell") as? NotificationTimeTableViewCell else {
fatalError("Cell Initialization failed")
}
cell.notificationStartTimeLabel.text = "Break notification start before"
cell.notificationEndTimeLabel.text = "Break notification end before"
if UserDefaults.standard.string(forKey: UserDefaultsKey.breakStart) == nil {
UserDefaults.standard.set("01", forKey: UserDefaultsKey.breakStart)
UserDefaults.standard.set("01", forKey: UserDefaultsKey.breakEnd)
}
cell.startTimeTextField.text = UserDefaults.standard.string(forKey:
UserDefaultsKey.breakStart)! + " min"
cell.endTimeTextField.text = UserDefaults.standard.string(forKey:
UserDefaultsKey.breakEnd)! + " min"
cell.startTimeTextField.tag = indexPath.section
cell.endTimeTextField.tag = indexPath.section
cell.timePickerDelegate = self

cell.startIndex = cell.timeList.index(of: UserDefaults.standard.string(forKey:


UserDefaultsKey.breakStart) ?? "01") ?? 0
cell.startPickerView?.selectRow(cell.startIndex, inComponent: 0, animated: true)
cell.endIndex = cell.timeList.index(of: UserDefaults.standard.string(forKey:
UserDefaultsKey.breakEnd) ?? "01") ?? 0
cell.endPickerView?.selectRow(cell.endIndex, inComponent: 0, animated: true)
cell.startString = UserDefaults.standard.string(forKey:
UserDefaultsKey.breakStart)
cell.endString = UserDefaults.standard.string(forKey: UserDefaultsKey.breakEnd)

if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == false


{
cell.isHidden = true
} else {
if UserDefaults.standard.bool(forKey: UserDefaultsKey.breakState) == false {
cell.isHidden = true
} else {
cell.isHidden = false
23

}
Page

}
return cell
}

case .TaskNotifications:
switch NotificationTime(index: indexPath.row) {
case .notificationType:
guard let cell = tableView.dequeueReusableCell(withIdentifier:
"NotificationsEnabledCell") as? NotificationsEnabledCell else {
fatalError("Cell Initialization failed")
}
cell.notificationEnabledSwitch.addTarget(self, action:
#selector(taskNotificationsEnabledStateChanged(switchState:)), for: .valueChanged)
cell.notificationEnabledLabel.text = "Task Notification"
if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == false
{
cell.notificationEnabledSwitch.setOn(false, animated: true)
} else {
cell.notificationEnabledSwitch.setOn(UserDefaults.standard.bool(forKey:
UserDefaultsKey.taskState), animated: true)
}
return cell
case .notificationTime:
guard let cell = tableView.dequeueReusableCell(withIdentifier:
"NotificationTimeTableViewCell") as? NotificationTimeTableViewCell else {
fatalError("Cell Initialization failed")
}
cell.notificationStartTimeLabel.text = "Task notification start before"
cell.notificationEndTimeLabel.text = "Task notification end before"
cell.notificationStartTimeLabel.text = "Task notification start before"
cell.notificationEndTimeLabel.text = "Task notification end before"
if UserDefaults.standard.string(forKey: UserDefaultsKey.taskStart) == nil {
UserDefaults.standard.set("01", forKey: UserDefaultsKey.taskStart)
UserDefaults.standard.set("01", forKey: UserDefaultsKey.taskEnd)
}
cell.startTimeTextField.text = UserDefaults.standard.string(forKey:
UserDefaultsKey.taskStart)! + " min"
cell.endTimeTextField.text = UserDefaults.standard.string(forKey:
UserDefaultsKey.taskEnd)! + " min"
cell.startTimeTextField.tag = indexPath.section
cell.endTimeTextField.tag = indexPath.section
cell.timePickerDelegate = self

cell.startIndex = cell.timeList.index(of: UserDefaults.standard.string(forKey:


UserDefaultsKey.taskStart) ?? "01") ?? 0
cell.startPickerView?.selectRow(cell.startIndex, inComponent: 0, animated: true)
cell.endIndex = cell.timeList.index(of: UserDefaults.standard.string(forKey:
UserDefaultsKey.taskEnd) ?? "01") ?? 0
cell.endPickerView?.selectRow(cell.endIndex, inComponent: 0, animated: true)
24

cell.startString = UserDefaults.standard.string(forKey: UserDefaultsKey.taskStart)


Page

cell.endString = UserDefaults.standard.string(forKey: UserDefaultsKey.taskEnd)


if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == false
{
cell.isHidden = true
} else {
if UserDefaults.standard.bool(forKey: UserDefaultsKey.taskState) == false {
cell.isHidden = true
} else {
cell.isHidden = false
}
}
return cell
}
}
}
}

extension NotificationSettingsViewController: TimePickerProtocol {

// MARK :- Protocol function


func pickStartTime(pickerValue: String, sectionTag: Int) {
switch NotificationSettingsSections(id: sectionTag) {
case .NotificationEnabled:
break
case .ShiftNotifications:
UserDefaults.standard.set(pickerValue, forKey: UserDefaultsKey.shiftStart)
case .BreakNotifications:
UserDefaults.standard.set(pickerValue, forKey: UserDefaultsKey.breakStart)
case .TaskNotifications:
UserDefaults.standard.set(pickerValue, forKey: UserDefaultsKey.taskStart)
}
notificationSettingsTableView.reloadData()
NotificationManager.notificationManager.updateNotificationSetting()
}

func pickEndTime(pickerValue: String, sectionTag: Int) {


switch NotificationSettingsSections(id: sectionTag) {
case .NotificationEnabled:
break
case .ShiftNotifications:
UserDefaults.standard.set(pickerValue, forKey: UserDefaultsKey.shiftEnd)
case .BreakNotifications:
UserDefaults.standard.set(pickerValue, forKey: UserDefaultsKey.breakEnd)
case .TaskNotifications:
UserDefaults.standard.set(pickerValue, forKey: UserDefaultsKey.taskEnd)
}
notificationSettingsTableView.reloadData()
NotificationManager.notificationManager.updateNotificationSetting()
25

}
Page

}
Training Plan Services:
Interfaces
interfacimport Foundation
import UIKit
import UserNotifications

enum NotificationType: String {


case TaskStart
case TaskEnd
case ShiftStart
case ShiftEnd
case BreakStart
case BreakEnd
}

class NotificationManager {
private var taskList: [ScheduledTask] = []
private var workShifts: [WorkShiftDetails] = []
private var breakShifts: [BreakDetails] = []
private var taskTimeList: [TaskTimes] = []

static var notificationManager: NotificationManager = NotificationManager()


var nsvcObject = NotificationSettingsViewController()

var breakSwitchState = UserDefaults.standard.bool(forKey:


UserDefaultsKey.breakState)
var taskSwitchState = UserDefaults.standard.bool(forKey: UserDefaultsKey.taskState)

private init() {

func manage() {
fetchCoreData(callback: {

})
let taskSwitchState = UserDefaults.standard.bool(forKey: UserDefaultsKey.taskState)
if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == true {
if workShifts.count > 0 {
setUpShiftNotification()
if taskList.count > 0 && taskSwitchState == true {
setUpNotifications()
} else {
print("Task list is empty or task notification is off.")
}
} else {
print("Shift list is empty.")
26

}
} else {
Page

print("Notification is off.")
}
}

func updateNotificationSetting() {
fetchCoreData(callback: {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
let taskSwitchState = UserDefaults.standard.bool(forKey:
UserDefaultsKey.taskState)
if UserDefaults.standard.bool(forKey: UserDefaultsKey.notificationState) == true {
if self.workShifts.count > 0 {
self.setUpShiftNotification()
if self.taskList.count > 0 && taskSwitchState == true {
self.setUpNotifications()
} else {
print("Task list is empty or task notification is off.")
}
} else {
print("Shift list is empty.")
}
} else {
print("Notification is off.")
}
})

private func fetchCoreData(callback: @escaping


() -> Void) {
DispatchQueue.main.async {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let context = appDelegate.persistentContainer.viewContext
do {
self.taskList = try context.fetch(ScheduledTask.fetchRequest())
self.taskList = self.sortTasks(tasks: self.taskList)
self.workShifts = try context.fetch(WorkShiftDetails.fetchRequest())
if self.workShifts.count == 0 {
_ = WorkShiftDetails(context: context)
appDelegate.saveContext()
self.fetchCoreData(callback: {
})
}
self.breakShifts = try context.fetch(BreakDetails.fetchRequest())
self.taskTimeList = try context.fetch(TaskTimes.fetchRequest())
callback()
} catch {
print(error.localizedDescription)
27

}
Page

}
}

private func sortTasks(tasks: [ScheduledTask]) -> [ScheduledTask] {


return tasks.sorted(by: {$0.commanId < $1.commanId})
}

private func setUpShiftNotification() {


let shiftSwitchState = UserDefaults.standard.bool(forKey:
UserDefaultsKey.shiftState)
if shiftSwitchState == true {
for index in 0..<workShifts.count {
createNotification(forIndex: index, ofType: .ShiftStart)
createNotification(forIndex: index, ofType: .ShiftEnd)
}
} else {
print("Shift notification is off.")
}
}

private func setUpNotifications() {


let breakSwitchState = UserDefaults.standard.bool(forKey:
UserDefaultsKey.breakState)
for index in 0..<taskList.count {
createNotification(forIndex: index, ofType: .TaskStart)
createNotification(forIndex: index, ofType: .TaskEnd)
}

if breakShifts.count > 0 && breakSwitchState == true {


for index in 0..<breakShifts.count {
createNotification(forIndex: index, ofType: .BreakStart)
createNotification(forIndex: index, ofType: .BreakEnd)
}
} else {
print("Break shift is empty or break notification is off.")
}
}

private func createNotification(forIndex index: Int, ofType type: NotificationType) {


let notificationContent = setNotificationContent(on: index, for: type)
guard let notificationTrigger = setNotificationTrigger(on: index, for: type) else {
return
}
let notificationRequestIdentifier = "\(type.rawValue)\(index)"
let notificationRequest = UNNotificationRequest(identifier:
notificationRequestIdentifier, content: notificationContent, trigger: notificationTrigger)
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
print(error as Any)
}
28

print(notificationRequest)
Page

}
private func setNotificationContent(on index: Int, for type: NotificationType) ->
UNMutableNotificationContent {
let content = UNMutableNotificationContent()
switch type {
case .TaskStart:
content.title = "Task about to start in \(UserDefaults.standard.string(forKey:
UserDefaultsKey.taskStart) ?? "") min"
content.body = taskList[index].projectDetails?.name ?? "Unknown Task"
content.sound = UNNotificationSound(named: "out.caf")
case .TaskEnd:
content.title = "Task about to end in \(UserDefaults.standard.string(forKey:
UserDefaultsKey.taskEnd) ?? "") min"
content.body = taskList[index].projectDetails?.name ?? "Unknown Task"
content.sound = UNNotificationSound(named: "out.caf")
case .ShiftStart:
content.title = "Shift about to start in \(UserDefaults.standard.string(forKey:
UserDefaultsKey.shiftStart) ?? "") min"
content.sound = UNNotificationSound(named: "out.caf")
case .ShiftEnd:
content.title = "Shift about to end in \(UserDefaults.standard.string(forKey:
UserDefaultsKey.shiftEnd) ?? "") min"
content.sound = UNNotificationSound(named: "out.caf")
case .BreakStart:
content.title = "Break about to start in \(UserDefaults.standard.string(forKey:
UserDefaultsKey.breakStart) ?? "") min"
content.sound = UNNotificationSound(named: "out.caf")
case .BreakEnd:
content.title = "Break about to end in \(UserDefaults.standard.string(forKey:
UserDefaultsKey.breakEnd) ?? "") min"
content.sound = UNNotificationSound(named: "out.caf")
}
content.badge = 1
return content
}

private func setNotificationTrigger(on index: Int, for type: NotificationType) ->


UNNotificationTrigger? {
let activityTime: Date
let offsetDurationInSeconds: Int
let calendar = Calendar.current
switch type {
case .TaskStart:
activityTime = taskTimeList[index].startTime!
if let taskNotificationStartTime = UserDefaults.standard.string(forKey:
UserDefaultsKey.taskStart) {
offsetDurationInSeconds = (Int(taskNotificationStartTime) ?? 0) *
ApplicationConstant.sixtySecond
29

} else {
Page

offsetDurationInSeconds = ApplicationConstant.sixtySecond
}
case .TaskEnd:
activityTime = taskTimeList[index].endTime!
if let taskEndNotificationTime = UserDefaults.standard.string(forKey:
UserDefaultsKey.taskEnd) {
offsetDurationInSeconds = (Int(taskEndNotificationTime) ?? 0) *
ApplicationConstant.sixtySecond
} else {
offsetDurationInSeconds = ApplicationConstant.sixtySecond
}
case .ShiftStart:
activityTime = workShifts[index].startTime!
if let shiftNotificationTime = UserDefaults.standard.string(forKey:
UserDefaultsKey.shiftStart) {
offsetDurationInSeconds = (Int(shiftNotificationTime) ?? 0) *
ApplicationConstant.sixtySecond
} else {
offsetDurationInSeconds = ApplicationConstant.sixtySecond
}
case .ShiftEnd:
activityTime = workShifts[index].endTime!
if let shiftNotificationTime = UserDefaults.standard.string(forKey:
UserDefaultsKey.shiftEnd) {
offsetDurationInSeconds = (Int(shiftNotificationTime) ?? 0) *
ApplicationConstant.sixtySecond
} else {
offsetDurationInSeconds = ApplicationConstant.sixtySecond
}
case .BreakStart:
guard let breakCurrentTime = breakShifts[index].startTime else {
return nil
}
activityTime = breakCurrentTime
if let breakNotificationTime = UserDefaults.standard.string(forKey:
UserDefaultsKey.breakStart) {
offsetDurationInSeconds = (Int(breakNotificationTime) ?? 0) *
ApplicationConstant.sixtySecond
} else {
offsetDurationInSeconds = ApplicationConstant.sixtySecond
}
case .BreakEnd:
guard let breakEndTime = breakShifts[index].endTime else {
return nil
}
activityTime = breakEndTime
if let breakNotificationTime = UserDefaults.standard.string(forKey:
UserDefaultsKey.breakEnd) {
offsetDurationInSeconds = (Int(breakNotificationTime) ?? 0) *
30

ApplicationConstant.sixtySecond
Page

} else {
offsetDurationInSeconds = ApplicationConstant.sixtySecond
}
}
let triggerDateComponents = calendar.dateComponents([.hour, .minute], from:
activityTime.adjust(.second, offset: -offsetDurationInSeconds))
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDateComponents,
repeats: false)
return trigger
}
}

31
Page
Page
32
Page
33
7. TESTING

The testing for all the stories, bugs are performed in same way. The cycle repeats in the
end of every sprint ie. 15 days. For the future release. And in every 3 months team do
the thorough testing for the next deployed build.

● FUNCTIONAL TESTING

This testing ensures that the requirements are properly satisfied by the
application or not. Various inputs are passed with different values to check the
database behavior and other specifications of the application.

● UNIT TESTING

In unit testing we take a module and test it one by one and try to cover all
possiblities to check if our code is working fine or not.

● TESTING PERFORMED BY QA

First the code is deployed in QA environment, there the testing is performed.


Once it performs tests in all conditions, then the team mark it as passed.

Thus, it goes to the production release, and finally observed for few days, so
that it does not create any problem.

34
Page
8. IMPLEMENTATION

● IMPLEMENTATION OF THE PROJECT

Each time designing the new changes or fixing the bugs, proper analyzing of
code flow is done. The need to understand the code flow is must, and then only
anything can be implemented, considering the actual model in which the
application is build.

Then it is necessary to understand the requirements of the user well, to avoid


any last-minute dissatisfaction. Meetings are scheduled to discuss about the
fixes and changes, that are to take place and understand the needs well.

● CONVERSION PLAN

The changes that are to be made are listed down and accordingly the coding is
done.

For fixing a bug, the whole point of error is traced by debugging the code and
finding the root cause of issue. Once the cause is known, it is fixed and sent for
testing.

For adding a new feature or functionality, prior to implementing the actual one,
a demo is prepared. Later when the demo is ready, a meeting is scheduled with
the user and displayed, to know if any changes are required. When the changes
are approved by the user, then the final implementation takes place.

● POST IMPLEMENTATION

Once everything is implemented and approved, the code is deployed for testing.
After passing the testing phase, it is finally released for users to use. Then it is
kept under surveillance for some time, to assure the proper functioning of the
application.
35
Page
9. PROJECT LEGACY

1. FUSIONCX

● CURRENT STATUS OF PROJECT


The project is available to customers to use. The project is being improved
version vise to make it better and viable.

● REMAINING AREAS OF CONCERN


The product deals with a changes and updates which pleases the cutomer, so the
main concern is to make the modifications which are on regular basis to be more
advanced, and how can they easily be done by a lot more of internal process and
jobs, rather than human needs. More the Automation, the better experience user
gets.

● TECHNICAL AND MANAGERIAL LESSONS LEARNT


Technical aspects: Learnt how to develop web application using GWTP with
MVP model.
Managerial aspects: Learnt how to implement the code within certain
amount of time and work as a team.

2. OMNI

● CURRENT STATUS OF PROJECT


The project is in development state but soon ready to get release in market. It
will perform operations like Fusion but in lighter and smoother way. And built
in Microservices way. Customer can choose how he wants to manage its
operations.

● REMAINING AREAS OF CONCERN


To make as stable as possible before giving to market.

● TECHNICAL AND MANAGERIAL LESSONS LEARNT


Technical aspects: Learnt how to develop web application using GWTP
using Microservices approach and MVP pattern of designing.
Managerial aspects: Learnt how to work as a team and plan work taking time
into consideration.
36
Page
10. REFERENCES

● http://www.github.com
● http://www.stackoverflow.com
● http://www.youtube.com
● http://apple.developers.com
● http://www.swiftTutorials.com

37
Page