terminal-app 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +6 -1
- data/README.md +175 -19
- data/activities.txt +2 -0
- data/images/Terminal-app.png +0 -0
- data/images/check-completed.png +0 -0
- data/images/delete.png +0 -0
- data/images/get-stats.png +0 -0
- data/images/main-menu.png +0 -0
- data/images/show.png +0 -0
- data/lib/Activity.rb +23 -0
- data/lib/AppController.rb +178 -0
- data/lib/Display.rb +52 -0
- data/lib/Model.rb +136 -0
- data/lib/app.rb +21 -0
- data/lib/helpers.rb +24 -0
- data/lib/terminal/app/version.rb +1 -1
- data/lib/testing.rb +140 -0
- data/lib/users/a.csv +1 -0
- data/lib/users/hdjsafk.csv +1 -0
- data/{activities.csv → lib/users/hfrhfuaerhfu.csv} +0 -0
- data/lib/users/hjfakj.csv +0 -0
- data/lib/users/tess.csv +6 -0
- metadata +21 -7
- data/Activity.rb +0 -11
- data/ActivityController.rb +0 -20
- data/ActivityModel.rb +0 -10
- data/lib/terminal/app.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27c4752b331bd2eea46392771bf6a214539eecf0df7642f8a32ded3a6251a67a
|
4
|
+
data.tar.gz: 54d7258ac1ee9411bef49ffefd86b63e69bad5cd1515e1db4c88b11dc7b99f69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12685863f2cb6c5d61ad66323117b6e571fab731d2789405e489f00c63a8bab081ce4f32fb5c13df9ecd4cc8a94370c1964da41f743bb066755529f3e4d7d6fd
|
7
|
+
data.tar.gz: a3f40df981cf82df2dd78aabcf8044289a1bbc891dc6629afc1d7ab6716bf18dd10665406f06550f461468f918dc67542b99423d73f339066b8a0e099a437abd
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,40 +1,196 @@
|
|
1
|
-
# Terminal::App
|
2
1
|
|
3
|
-
|
2
|
+
Application Source Code
|
3
|
+
---
|
4
|
+
https://github.com/tessssssssy/terminal-app
|
4
5
|
|
5
|
-
|
6
|
+
Purpose of the application
|
7
|
+
---
|
8
|
+
My application is an exercise planning and recording app. The application has multiple features. Users can schedule future workouts and log past workouts, recording workout type, distance, duration and date. They can also check off workouts as completed and view workout stats
|
6
9
|
|
7
|
-
|
10
|
+
What problem is this app trying to solve
|
11
|
+
---
|
8
12
|
|
9
|
-
|
13
|
+
This application aims to be a motivational tool to encourage people to get more exercise. It builds users accountability to an exercise plan by allowing them to plan future workouts and check them off as they are completed.
|
14
|
+
|
15
|
+
Target Audience
|
16
|
+
---
|
17
|
+
The app is intended for anyone who is interested in starting an exercise plan and want to record their workouts. The app is focused on exercises with the ability to record time and distance, including running, cycling, swimming, walking and hiking so would be particularly suited to people who are interested in those activities.
|
18
|
+
|
19
|
+
How the audience will use the application
|
20
|
+
---
|
21
|
+
Users will use the application to create their own exercise plan, log and check off completed workouts and to calculate and monitor their monthly activity totals.
|
22
|
+
|
23
|
+
Application Features
|
24
|
+
---
|
25
|
+
1. Users can log completed workouts and record details icluding:
|
26
|
+
|
27
|
+
- workout type: run, ride, swim or walk/hike
|
28
|
+
- distance
|
29
|
+
- duration
|
30
|
+
- date completed
|
31
|
+
|
32
|
+
2. Users can schedule future workouts in the same way they log past ones. Recording the planned workout type, distance, duration and the date they want to complete it.
|
33
|
+
|
34
|
+
3. View a table of all workouts and their details. These are colour coded, with different colours for completed, incomplete past workouts and future planned workouts.
|
35
|
+
|
36
|
+
4. Users can check off completed activities. This will change the colour of the activity in the view table. When a past activity is logged, it is checked completed automatically.
|
37
|
+
|
38
|
+
5. Get workout stats. Users can view the total distance and duration for each workout type, and see their longest workouts by distance and duration. Users can choose to see totals and personal records for a specific months or view all.
|
39
|
+
|
40
|
+
User Interaction
|
41
|
+
---
|
42
|
+
1. Users will type their name/username as a command line argument when they run the application
|
43
|
+
|
44
|
+
2. The user will choose an option from a main menu:
|
45
|
+
- add activity
|
46
|
+
- show activities
|
47
|
+
- check completed activity
|
48
|
+
- get stats
|
49
|
+
- quit: quits the application
|
50
|
+
|
51
|
+
3. The user will then be directed to one of the sub menus:
|
52
|
+
- add activity: asked to input activity type, distance, duration and date
|
53
|
+
- show activities: displays a table listing all the users activities
|
54
|
+
- check-completed-activities: asks the user for a date, then shows a list of activities on that date for the user to check off
|
55
|
+
- get stats: asks user to enter activity type and month, then shown a table of activity totals/personal records
|
56
|
+
|
57
|
+
4. If the user ever enters an invalid input, the application will detect it and ask them to try again
|
58
|
+
|
59
|
+
User Interaction Diagram
|
60
|
+
---
|
61
|
+

|
62
|
+
|
63
|
+
Implementation Plan
|
64
|
+
---
|
65
|
+
Develop an implementation plan which:
|
66
|
+
- outlines how each feature will be implemented and a checklist of tasks for each feature
|
67
|
+
- prioritise the implementation of different features, or checklist items within a feature
|
68
|
+
- provide a deadline, duration or other time indicator for each feature or checklist/checklist-item
|
69
|
+
|
70
|
+
Utilise a suitable project management platform to track this implementation plan
|
71
|
+
|
72
|
+
> Your checklists for each feature should have at least 5 items.
|
73
|
+
|
74
|
+
Structure
|
75
|
+
---
|
76
|
+
The application will be written using a Model, View, Controller (MVC) type structure
|
77
|
+
|
78
|
+
- The model will interact with and manipulate user data taken from user input and stored in
|
79
|
+
a csv file. It will also send data to the display class to display to the user
|
80
|
+
|
81
|
+
- The controller is responsible for taking user input and controlling the flow of the application. It
|
82
|
+
sends user input to the model where it is processed and stored on a csv file
|
83
|
+
|
84
|
+
- The display class will take user data from the model and display it in a visually appealing way to the user
|
85
|
+
|
86
|
+
- An Activity class will be used to create a blueprint for activity objects
|
87
|
+
|
88
|
+
- A csv file will be allocated to each user to store their activities
|
89
|
+
|
90
|
+
Features
|
91
|
+
---
|
92
|
+
1. Main Menu
|
93
|
+
- create a menu method in controller class
|
94
|
+
- direct user to various sub menus/features
|
95
|
+
- use a loop to continue showing user menu options until they quit app
|
96
|
+
- install tty prompt gem to create more user friendly menu
|
97
|
+
- handle user input errors
|
98
|
+
|
99
|
+
|
100
|
+
2. Add Activity
|
101
|
+
- Create an activity class with type, distance, duration, date parameters
|
102
|
+
- Create a method in controller that takes user input
|
103
|
+
- Create method in model that processes user input and creates activity object
|
104
|
+
- Append new activity to csv file
|
105
|
+
|
106
|
+
3. Show Activities
|
107
|
+
- need a method to get activities from csv file and add to an array
|
108
|
+
- method in display class to display data in a presentable way
|
109
|
+
- use terminal-table gem to display the activities as a table
|
110
|
+
- sort data to show newest activities first
|
111
|
+
|
112
|
+
4. Check off completed activities
|
113
|
+
- create a method to search for activities by date
|
114
|
+
- method to handle user input
|
115
|
+
- method to take selected activity and set completed
|
116
|
+
- change color of completed activity in display class
|
117
|
+
- auto set complete if a user logs a past activity
|
118
|
+
|
119
|
+
5. Delete Activity
|
120
|
+
- method to search for activity to delete
|
121
|
+
- handle user input
|
122
|
+
- remove activity from activities array
|
123
|
+
- method to update the csv file
|
124
|
+
- redirect to main menu if no activities to delete
|
125
|
+
|
126
|
+
6. Get Stats
|
127
|
+
- method to calculate total distance/time
|
128
|
+
- Display method to show totals
|
129
|
+
- method to find longest activities
|
130
|
+
- Display method to show longest activities
|
131
|
+
- method to handle user input - sub menu to enter activity
|
132
|
+
type, month
|
133
|
+
|
134
|
+
Project Management
|
135
|
+
---
|
136
|
+
I will be utilizing trello for project management
|
137
|
+
|
138
|
+
Documentation
|
139
|
+
---
|
140
|
+
|
141
|
+
Installation
|
142
|
+
|
143
|
+
```bash
|
144
|
+
|
145
|
+
gem install terminal-app
|
146
|
+
|
147
|
+
```
|
148
|
+
|
149
|
+
Gemfile
|
10
150
|
|
11
151
|
```ruby
|
12
|
-
|
152
|
+
|
153
|
+
gem 'terminal-app', '~> 0.1.0'
|
154
|
+
|
155
|
+
```
|
156
|
+
|
157
|
+
Install Dependencies
|
158
|
+
|
159
|
+
```bash
|
160
|
+
bundle install
|
161
|
+
```
|
162
|
+
|
163
|
+
Running the application
|
164
|
+
|
165
|
+
```bash
|
166
|
+
ruby terminal-app <username>
|
13
167
|
```
|
168
|
+
Instructions
|
14
169
|
|
15
|
-
|
170
|
+
1. Enter a username as a command line argument
|
16
171
|
|
17
|
-
|
172
|
+
2. If it is a new user, a file will be created to store the users activities, otherwise, the username will be matched to their corresponding csv file with their stored data.
|
18
173
|
|
19
|
-
|
174
|
+
Command Line Interface
|
175
|
+
---
|
20
176
|
|
21
|
-
|
177
|
+
Main Menu
|
22
178
|
|
23
|
-
|
179
|
+

|
24
180
|
|
25
|
-
|
181
|
+
Show Activities
|
26
182
|
|
27
|
-
|
183
|
+

|
28
184
|
|
29
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
185
|
|
31
|
-
|
186
|
+
Check Completed sub-menu
|
32
187
|
|
33
|
-
|
188
|
+

|
34
189
|
|
35
|
-
|
190
|
+
Delete Activity sub-menu
|
36
191
|
|
192
|
+

|
37
193
|
|
38
|
-
|
194
|
+
Get Stats
|
39
195
|
|
40
|
-
|
196
|
+

|
data/activities.txt
ADDED
Binary file
|
Binary file
|
data/images/delete.png
ADDED
Binary file
|
Binary file
|
Binary file
|
data/images/show.png
ADDED
Binary file
|
data/lib/Activity.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class Activity
|
4
|
+
attr_reader :type, :distance, :duration, :date
|
5
|
+
attr_accessor :completed
|
6
|
+
def initialize(type, distance, duration, date)
|
7
|
+
@type = type
|
8
|
+
@distance = distance
|
9
|
+
@duration = duration
|
10
|
+
@date = date
|
11
|
+
@completed = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def complete_activity
|
15
|
+
@completed = true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require_relative 'Model.rb'
|
2
|
+
require_relative 'Display.rb'
|
3
|
+
require_relative 'helpers.rb'
|
4
|
+
require_relative 'Activity.rb'
|
5
|
+
require 'date'
|
6
|
+
require "tty-prompt"
|
7
|
+
|
8
|
+
|
9
|
+
class AppController
|
10
|
+
|
11
|
+
# run at start of program to check if new user
|
12
|
+
# either create a file for new user or get activities for returning user
|
13
|
+
def self.check_user(user_name)
|
14
|
+
if File.exist?("users/#{user_name}.csv")
|
15
|
+
Model.get_activities(user_name)
|
16
|
+
self.menu(user_name)
|
17
|
+
else
|
18
|
+
Model.add_user(user_name)
|
19
|
+
self.menu(user_name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# main menu - run straight after user check
|
24
|
+
def self.menu(user)
|
25
|
+
while true
|
26
|
+
prompt = TTY::Prompt.new
|
27
|
+
answer = prompt.select("Choose an option: ", %w(add-activity show-activities check-completed-activity delete-activity get-stats quit))
|
28
|
+
if answer == 'add-activity'
|
29
|
+
self.add_activity(user)
|
30
|
+
elsif answer == 'show-activities'
|
31
|
+
Display.show_activities(user)
|
32
|
+
elsif answer == 'check-completed-activity'
|
33
|
+
# self.find_activities(user)
|
34
|
+
self.check_completed(user)
|
35
|
+
elsif answer == 'get-stats'
|
36
|
+
self.get_stats(user)
|
37
|
+
elsif answer == 'delete-activity'
|
38
|
+
self.delete_activity(user)
|
39
|
+
elsif answer == 'quit'
|
40
|
+
exit
|
41
|
+
else
|
42
|
+
puts "Invalid Input"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.get_activities_by_date(user)
|
48
|
+
begin
|
49
|
+
puts "Activity date: (today or yyyy-mm-dd): "
|
50
|
+
date = gets.chomp
|
51
|
+
if date == "today"
|
52
|
+
date = Date.today.to_s
|
53
|
+
else
|
54
|
+
Date.parse(date)
|
55
|
+
end
|
56
|
+
activities = Model.search_activities(user, date) #an array of activities
|
57
|
+
raise "No activities on that date" if activities.length == 0
|
58
|
+
rescue Date::Error, RuntimeError
|
59
|
+
puts "Invalid date"
|
60
|
+
self.menu(user)
|
61
|
+
end
|
62
|
+
return activities
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.select_activity(user, activities)
|
66
|
+
#activities = self.get_activities_by_date(user)
|
67
|
+
prompt = TTY::Prompt.new
|
68
|
+
options = %w(go-back)
|
69
|
+
activities.each do |activity|
|
70
|
+
options << "#{activity.type}-#{activity.distance}-#{activity.duration}-#{activity.date}"
|
71
|
+
end
|
72
|
+
selected_activity = prompt.select("Select Activity: ", options)
|
73
|
+
# p selected_activity
|
74
|
+
if selected_activity == 'go-back'
|
75
|
+
self.menu(user)
|
76
|
+
end
|
77
|
+
activities.each do |activity|
|
78
|
+
activity_string = "#{activity.type}-#{activity.distance}-#{activity.duration}-#{activity.date}"
|
79
|
+
if activity_string == selected_activity
|
80
|
+
return activity
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.find_activities(user)
|
86
|
+
begin
|
87
|
+
puts "Activity date: (today or yyyy-mm-dd): "
|
88
|
+
date = gets.chomp
|
89
|
+
if date == "today"
|
90
|
+
date = Date.today.to_s
|
91
|
+
end
|
92
|
+
Date.parse(date)
|
93
|
+
activities = Model.search_activities(user, date) #an array of activities
|
94
|
+
raise "No activities on that date" if activities.length == 0
|
95
|
+
rescue Date::Error, RuntimeError
|
96
|
+
puts "Invalid date"
|
97
|
+
retry
|
98
|
+
end
|
99
|
+
prompt = TTY::Prompt.new
|
100
|
+
options = %w(go-back)
|
101
|
+
activities.each do |activity|
|
102
|
+
options << "#{activity.type}-#{activity.distance}-#{activity.duration}-#{activity.date}"
|
103
|
+
end
|
104
|
+
selected_activity = prompt.select("Select Activity: ", options)
|
105
|
+
if selected_activity == 'go-back'
|
106
|
+
self.menu(user)
|
107
|
+
end
|
108
|
+
activities.each do |activity|
|
109
|
+
activity_string = "#{activity.type}-#{activity.distance}-#{activity.duration}-#{activity.date}"
|
110
|
+
if activity_string == selected_activity
|
111
|
+
activity.completed = true
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.check_completed(user)
|
117
|
+
activities = self.get_activities_by_date(user)
|
118
|
+
activity = self.select_activity(user, activities)
|
119
|
+
activity.completed = true
|
120
|
+
Model.update_activities(user, activities)
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.delete_activity(user)
|
124
|
+
activities = self.get_activities_by_date(user)
|
125
|
+
activity = self.select_activity(user, activities)
|
126
|
+
Model.delete_activity(user, activity)
|
127
|
+
end
|
128
|
+
def self.add_activity(user)
|
129
|
+
prompt = TTY::Prompt.new
|
130
|
+
type = prompt.select("Select Activity: ", %w(run bike swim walk/hike))
|
131
|
+
begin
|
132
|
+
puts "Distance(kms): "
|
133
|
+
distance = gets.chomp.to_f
|
134
|
+
raise "Invalid Input" if distance == 0.0
|
135
|
+
rescue RuntimeError
|
136
|
+
puts "Please enter a number"
|
137
|
+
retry
|
138
|
+
end
|
139
|
+
begin
|
140
|
+
puts "Duration(mins): "
|
141
|
+
duration = gets.chomp.to_i
|
142
|
+
raise "Invalid Input" if duration == 0
|
143
|
+
rescue RuntimeError
|
144
|
+
puts "Please enter a number"
|
145
|
+
retry
|
146
|
+
end
|
147
|
+
# need to handle wrong user input
|
148
|
+
begin
|
149
|
+
puts "Date: (today or yyyy-mm-dd)"
|
150
|
+
date = gets.chomp
|
151
|
+
if date != "today"
|
152
|
+
Date.parse(date)
|
153
|
+
end
|
154
|
+
rescue Date::Error
|
155
|
+
puts "Invalid date"
|
156
|
+
retry
|
157
|
+
end
|
158
|
+
if date.downcase == "today"
|
159
|
+
date = Date.today.to_s
|
160
|
+
end
|
161
|
+
Model.add_activity(user, type, distance, duration, date)
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.get_stats(user)
|
165
|
+
prompt = TTY::Prompt.new
|
166
|
+
month = prompt.select("Choose an month: ", %w(All January February March April May June July August September October November December))
|
167
|
+
prompt = TTY::Prompt.new
|
168
|
+
type = prompt.select("Select Activity: ", %w(run bike swim walk/hike))
|
169
|
+
totals = Model.calculate_totals(user, type, month)
|
170
|
+
records = Model.find_longest(user, type, month)
|
171
|
+
Display.display_records(records[0], records[1])
|
172
|
+
Display.display_totals(totals[0], totals[1])
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
|
178
|
+
|
data/lib/Display.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'terminal-table'
|
2
|
+
require_relative 'Model.rb'
|
3
|
+
require_relative 'helpers.rb'
|
4
|
+
require 'tty-font'
|
5
|
+
require 'colorize'
|
6
|
+
|
7
|
+
# The display class interacts with data for the model and presents it
|
8
|
+
# in a visually appealing way to the user using colors and tables
|
9
|
+
|
10
|
+
class Display
|
11
|
+
|
12
|
+
# shows list of completed activities
|
13
|
+
def self.show_activities(user)
|
14
|
+
activities = Model.get_activities(user)
|
15
|
+
rows = []
|
16
|
+
activities.each do |a|
|
17
|
+
row = [a.type, a.distance, a.duration, a.date]
|
18
|
+
|
19
|
+
# if an activity is completed it will display green
|
20
|
+
if a.completed == 'true'
|
21
|
+
row = row.map do |cell|
|
22
|
+
cell.to_s.colorize(:green)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# if the activity is incomplete, it will turn red if the date has passed
|
27
|
+
if a.completed == false && is_in_past?(a.date)
|
28
|
+
row = row.map do |cell|
|
29
|
+
cell.to_s.colorize(:red)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rows << row
|
33
|
+
end
|
34
|
+
table = Terminal::Table.new :title => "Activity Log", :headings => ['Activity', 'Distance', 'Duration', 'Date'], :rows => rows
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.display_totals(distance, duration)
|
38
|
+
font = TTY::Font.new(:straight)
|
39
|
+
rows = [["#{distance}kms", "#{duration}"]]
|
40
|
+
table = Terminal::Table.new :title => font.write("Activity Totals").colorize(:cyan), :headings => ['Total Distance', 'Total Time'], :rows => rows
|
41
|
+
puts table
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.display_records(distance, duration)
|
45
|
+
font = TTY::Font.new(:straight)
|
46
|
+
rows = [["#{distance}kms", "#{duration}"]]
|
47
|
+
table = Terminal::Table.new :title => font.write("Personal Records").colorize(:magenta), :headings => ['Longest Distance', 'Longest Time'], :rows => rows
|
48
|
+
puts table
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
data/lib/Model.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require_relative 'Activity.rb'
|
2
|
+
require_relative 'helpers.rb'
|
3
|
+
require 'date'
|
4
|
+
require 'csv'
|
5
|
+
|
6
|
+
# The model class processes data from user input and csv files and interacts with the controller
|
7
|
+
|
8
|
+
class Model
|
9
|
+
@@activities = []
|
10
|
+
|
11
|
+
# create a file for a new user
|
12
|
+
def self.add_user(user)
|
13
|
+
csv = CSV.open("users/#{user}.csv", 'wb') do |csv|
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# parses activity data from users file
|
18
|
+
# uses to create new activity objects and add to activities array
|
19
|
+
def self.get_activities(user)
|
20
|
+
activities = File.open("users/#{user}.csv", "r").read.split("\n")
|
21
|
+
activities = activities.map do |activity|
|
22
|
+
activity.split(",")
|
23
|
+
end
|
24
|
+
|
25
|
+
@@activities = []
|
26
|
+
activities.each do |activity|
|
27
|
+
new_activity = Activity.new(activity[0], activity[1], activity[2], activity[3])
|
28
|
+
new_activity.completed = activity[4]
|
29
|
+
@@activities << new_activity
|
30
|
+
end
|
31
|
+
|
32
|
+
# sort activities by date
|
33
|
+
@@activities = @@activities.sort_by {|obj| obj.date.to_s.split('-').join('').to_i }
|
34
|
+
return @@activities.reverse # sort from newest to oldest
|
35
|
+
end
|
36
|
+
|
37
|
+
# iterates over activities array
|
38
|
+
# overwrites file with updated activities
|
39
|
+
def self.update_activities(user, activities)
|
40
|
+
CSV.open("users/#{user}.csv", "wb") do |file|
|
41
|
+
activities.each do |activity|
|
42
|
+
file << [activity.type, activity.distance, activity.duration, activity.date, activity.completed]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# adds a new activity
|
48
|
+
# append it to the users file
|
49
|
+
def self.add_activity(user, type, distance, duration, date)
|
50
|
+
activity = Activity.new(type, distance, duration, date)
|
51
|
+
if is_in_past?(activity.date)
|
52
|
+
activity.completed = true #checks activity completed if in the past
|
53
|
+
end
|
54
|
+
@@activities << activity
|
55
|
+
#appends to file
|
56
|
+
CSV.open("users/#{user}.csv", "a") do |file|
|
57
|
+
file << [activity.type, activity.distance, activity.duration, activity.date, activity.completed]
|
58
|
+
end
|
59
|
+
return @@activities
|
60
|
+
end
|
61
|
+
|
62
|
+
# search for activities by date
|
63
|
+
#returns array of activities that match date input
|
64
|
+
def self.search_activities(user, date)
|
65
|
+
matched = []
|
66
|
+
@@activities.each do |activity|
|
67
|
+
if activity.date == date && activity.completed == 'false'
|
68
|
+
matched << activity
|
69
|
+
end
|
70
|
+
end
|
71
|
+
return matched
|
72
|
+
end
|
73
|
+
|
74
|
+
# deletes an activity based on user selection
|
75
|
+
# updates the csv file to remove the deleted activity
|
76
|
+
def self.delete_activity(user, activity)
|
77
|
+
activities = self.get_activities(user)
|
78
|
+
activities = activities.select do |a|
|
79
|
+
a.type != activity.type || a.distance != activity.distance || a.duration != activity.duration
|
80
|
+
end
|
81
|
+
self.update_activities(user, activities)
|
82
|
+
end
|
83
|
+
|
84
|
+
# finds the users longest activities by time and distance
|
85
|
+
# returns an array with longest distance and longest time to send to display
|
86
|
+
def self.find_longest(user, type, month)
|
87
|
+
longest_distance = 0
|
88
|
+
longest_duration = 0
|
89
|
+
activities = self.get_activities(user)
|
90
|
+
activities.each do |activity|
|
91
|
+
month_num = activity.date.to_s.split('-')[1].to_i
|
92
|
+
if month == 'All' || month == Date::MONTHNAMES[month_num]
|
93
|
+
if activity.distance.to_f > longest_distance
|
94
|
+
longest_distance = activity.distance.to_f
|
95
|
+
end
|
96
|
+
if activity.duration.to_i > longest_duration
|
97
|
+
longest_duration = activity.duration.to_i
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
minutes = longest_duration % 60
|
102
|
+
hours = (longest_duration - minutes) / 60
|
103
|
+
return [longest_distance, "#{hours} hours #{minutes} mins"]
|
104
|
+
end
|
105
|
+
|
106
|
+
# calculates users total distance and time for a particular activity for a month (or all months)
|
107
|
+
# returns an array to send to display class
|
108
|
+
def self.calculate_totals(user, type, month)
|
109
|
+
distance = 0
|
110
|
+
duration = 0
|
111
|
+
activities = self.get_activities(user)
|
112
|
+
activities.each do |activity|
|
113
|
+
month_num = activity.date.to_s.split('-')[1].to_i
|
114
|
+
if activity.type == type && ( month == 'All' || month == Date::MONTHNAMES[month_num] )
|
115
|
+
distance += activity.distance.to_f
|
116
|
+
duration += activity.duration.to_i
|
117
|
+
end
|
118
|
+
end
|
119
|
+
minutes = duration % 60
|
120
|
+
hours = (duration - minutes) / 60
|
121
|
+
return [distance, "#{hours} hours #{minutes} mins"]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
|
135
|
+
|
136
|
+
|
data/lib/app.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative "terminal/app/version"
|
2
|
+
require_relative 'AppController.rb'
|
3
|
+
|
4
|
+
module Terminal
|
5
|
+
module App
|
6
|
+
class Error < StandardError; end
|
7
|
+
# Your code goes here...
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
if ARGV.length != 1
|
12
|
+
puts "One argument required"
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
# pass the user name into the terminal
|
16
|
+
user_name = ARGV[0]
|
17
|
+
ARGV.clear
|
18
|
+
# Entry point to the app
|
19
|
+
AppController.check_user(user_name)
|
20
|
+
# AppController.check_user
|
21
|
+
|
data/lib/helpers.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
#compares two date strings
|
3
|
+
def is_in_past?(date)
|
4
|
+
date_num = date.split('-').join('').to_i
|
5
|
+
today = Date.today.to_s.split('-').join('').to_i
|
6
|
+
if date_num < today
|
7
|
+
return true
|
8
|
+
else
|
9
|
+
return false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
#compares two date strings
|
14
|
+
def is_in_future?(date)
|
15
|
+
date_num = date.split('-').join('').to_i
|
16
|
+
today = Date.today.to_s.split('-').join('').to_i
|
17
|
+
if date_num > today
|
18
|
+
return true
|
19
|
+
else
|
20
|
+
return false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
data/lib/terminal/app/version.rb
CHANGED
data/lib/testing.rb
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
# require 'date'
|
2
|
+
|
3
|
+
# puts Date::MONTHNAMES[3]
|
4
|
+
|
5
|
+
# require 'terminal-table'
|
6
|
+
|
7
|
+
# # activities = Model.get_activities
|
8
|
+
# rows = []
|
9
|
+
# (1..5).each do |num|
|
10
|
+
# rows << [1,2,3,4,5,6,7]
|
11
|
+
# end
|
12
|
+
# table = Terminal::Table.new :title => "March",
|
13
|
+
# :headings => ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
|
14
|
+
# :rows => rows
|
15
|
+
# puts table
|
16
|
+
|
17
|
+
# require 'csv'
|
18
|
+
|
19
|
+
# # csv_text = File.read('activities.csv')
|
20
|
+
# # csv = CSV.parse(csv_text, :headers => false)
|
21
|
+
# # activities = []
|
22
|
+
# # csv.each do |row|
|
23
|
+
# # row_data = row.to_hash
|
24
|
+
# # if (row_data['country'] == 'Australia') && (row_data['subcountry'] == 'Victoria')
|
25
|
+
# # puts row_data
|
26
|
+
# # cities << row_data
|
27
|
+
# # end
|
28
|
+
# # end
|
29
|
+
# # puts cities.length
|
30
|
+
|
31
|
+
|
32
|
+
# # CSV.open("activities.csv", "wb") do |csv|
|
33
|
+
# # csv << ["row", "of", "CSV", "data"]
|
34
|
+
# # csv << ["another", "row"]
|
35
|
+
# # # ...
|
36
|
+
# # end
|
37
|
+
|
38
|
+
# # File.open("activities.txt", "a") do |file|
|
39
|
+
# # file << ["run", "10"]
|
40
|
+
# # end
|
41
|
+
|
42
|
+
# CSV.open('test.csv', 'wb') do |csv|
|
43
|
+
# csv << ['test file']
|
44
|
+
# end
|
45
|
+
|
46
|
+
# Date::MONTHNAMES[month_num]
|
47
|
+
|
48
|
+
# require "tty-prompt"
|
49
|
+
|
50
|
+
# prompt = TTY::Prompt.new
|
51
|
+
|
52
|
+
# answer = prompt.select("Choose your destiny?", %w(Scorpion Kano Jax))
|
53
|
+
# puts answer
|
54
|
+
# # =>
|
55
|
+
# duration = 320
|
56
|
+
# minutes = duration % 60
|
57
|
+
# hours = (duration - minutes) / 60
|
58
|
+
|
59
|
+
# puts "#{hours} hours #{minutes} mins"
|
60
|
+
|
61
|
+
# # Select drinks? (Use ↑/↓ arrow keys, press Space to select and Enter to finish)"
|
62
|
+
# # ‣ ⬡ vodka
|
63
|
+
# # ⬡ beer
|
64
|
+
# # ⬡ wine
|
65
|
+
# # ⬡ whisky
|
66
|
+
# # ⬡ bourbon
|
67
|
+
|
68
|
+
str = "fhdnajknfk"
|
69
|
+
puts str.to_f
|
70
|
+
|
71
|
+
require 'date'
|
72
|
+
date = Date.today.to_s
|
73
|
+
# date_num = date.split('-').join('').to_i
|
74
|
+
# p date
|
75
|
+
# p date_num
|
76
|
+
|
77
|
+
#takes in string checks if right format
|
78
|
+
# def valid_date?(date)
|
79
|
+
# return false if date.class != String
|
80
|
+
# return false if date.length != 10
|
81
|
+
# date_arr = date.split("-")
|
82
|
+
# return false if date.split("-") != 3
|
83
|
+
# return false if date_arr[1].to_i > 12
|
84
|
+
# date_arr.each do |str|
|
85
|
+
# if str.to_i == 0
|
86
|
+
# return false
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
# valid_date ="2020-03-10"
|
90
|
+
#length == 10
|
91
|
+
#.split('-') == 3
|
92
|
+
|
93
|
+
# p valid_date?(12424)
|
94
|
+
|
95
|
+
#compares two date strings
|
96
|
+
def compare_dates(d1, d2)
|
97
|
+
num_1 = d1.split('-').join('').to_i
|
98
|
+
num_2 = d2.split('-').join('').to_i
|
99
|
+
if num_1 > num_2
|
100
|
+
return num_1
|
101
|
+
else
|
102
|
+
return num_2
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
require "tty-prompt"
|
109
|
+
require_relative 'Model.rb'
|
110
|
+
|
111
|
+
activities = Model.search_activities('tess', '2020-03-11') #an array of activities
|
112
|
+
p activities
|
113
|
+
prompt = TTY::Prompt.new
|
114
|
+
activity_strings = []
|
115
|
+
activities.each do |activity|
|
116
|
+
activity_strings << "#{activity.type}-#{activity.distance}-#{activity.duration}-#{activity.date}"
|
117
|
+
end
|
118
|
+
|
119
|
+
p activity_strings
|
120
|
+
# choices = %w()
|
121
|
+
# activities.each do |activity|
|
122
|
+
# choices << "activity" #"#{activity.type}-#{activity.distance}-#{activity.duration}-#{activity.date}"
|
123
|
+
# end
|
124
|
+
# selected_activity = prompt.select("Select Activity: ", choices)
|
125
|
+
# prompt.select("Choose your destiny?") do |menu|
|
126
|
+
# menu.choice activity_strings[0] , 1
|
127
|
+
# menu.choice 'Kano', 2
|
128
|
+
# menu.choice 'Jax', -> { 'Nice choice captain!' }
|
129
|
+
# end
|
130
|
+
# # =>
|
131
|
+
#
|
132
|
+
# Select drinks? (Use ↑/↓ arrow keys, press Space to select and Enter to finish)"
|
133
|
+
# ‣ ⬡ vodka
|
134
|
+
# ⬡ beer
|
135
|
+
# ⬡ wine
|
136
|
+
# ⬡ whisky
|
137
|
+
# ⬡ bourbon
|
138
|
+
|
139
|
+
puts Date.parse('2020-43-10')
|
140
|
+
puts Date.parse(Date.today)
|
data/lib/users/a.csv
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
run,8.0,30,2020-03-12,false
|
@@ -0,0 +1 @@
|
|
1
|
+
ride,40.0,120,2020-03-11
|
File without changes
|
File without changes
|
data/lib/users/tess.csv
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terminal-app
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tessssssssy
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: my gem
|
14
14
|
email:
|
@@ -20,19 +20,33 @@ files:
|
|
20
20
|
- ".gitignore"
|
21
21
|
- ".rspec"
|
22
22
|
- ".travis.yml"
|
23
|
-
- Activity.rb
|
24
|
-
- ActivityController.rb
|
25
|
-
- ActivityModel.rb
|
26
23
|
- Gemfile
|
27
24
|
- Gemfile.lock
|
28
25
|
- LICENSE.txt
|
29
26
|
- README.md
|
30
27
|
- Rakefile
|
31
|
-
- activities.
|
28
|
+
- activities.txt
|
32
29
|
- bin/console
|
33
30
|
- bin/setup
|
34
|
-
-
|
31
|
+
- images/Terminal-app.png
|
32
|
+
- images/check-completed.png
|
33
|
+
- images/delete.png
|
34
|
+
- images/get-stats.png
|
35
|
+
- images/main-menu.png
|
36
|
+
- images/show.png
|
37
|
+
- lib/Activity.rb
|
38
|
+
- lib/AppController.rb
|
39
|
+
- lib/Display.rb
|
40
|
+
- lib/Model.rb
|
41
|
+
- lib/app.rb
|
42
|
+
- lib/helpers.rb
|
35
43
|
- lib/terminal/app/version.rb
|
44
|
+
- lib/testing.rb
|
45
|
+
- lib/users/a.csv
|
46
|
+
- lib/users/hdjsafk.csv
|
47
|
+
- lib/users/hfrhfuaerhfu.csv
|
48
|
+
- lib/users/hjfakj.csv
|
49
|
+
- lib/users/tess.csv
|
36
50
|
- terminal-app.gemspec
|
37
51
|
homepage: https://github.com/tessssssssy/terminal-app
|
38
52
|
licenses:
|
data/Activity.rb
DELETED
data/ActivityController.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require_relative 'ActivityModel'
|
2
|
-
|
3
|
-
class ActivityController
|
4
|
-
def choose_option
|
5
|
-
puts "Choose an option:"
|
6
|
-
puts "1 to add an activity"
|
7
|
-
puts "2 to view activities"
|
8
|
-
return gets.chomp.to_i
|
9
|
-
end
|
10
|
-
|
11
|
-
def add_activity
|
12
|
-
puts "Activity type: "
|
13
|
-
type = gets.chomp
|
14
|
-
puts "Distance(kms): "
|
15
|
-
distance = gets.chomp.to_f
|
16
|
-
puts "Duration(mins): "
|
17
|
-
duration = gets.chomp.to_i
|
18
|
-
ActivityModel.add_activity(type, distance, duration)
|
19
|
-
end
|
20
|
-
end
|
data/ActivityModel.rb
DELETED