Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
SRCT
whats-open-android
Commits
bd2ad8b7
Commit
bd2ad8b7
authored
Jan 05, 2017
by
Robert Hitt
Browse files
Refactored the app to be more MVP-ey
- Should be much much easier to test and reuse logic stuff
parent
e09e499f
Changes
9
Hide whitespace changes
Inline
Side-by-side
.gitignore
View file @
bd2ad8b7
...
...
@@ -34,7 +34,7 @@ captures/
# Intellij
*.iml
.idea
/
.idea
# Keystore files
*.jks
...
...
app/src/main/java/srct/whatsopen/ui/FacilityView.java
0 → 100644
View file @
bd2ad8b7
package
srct.whatsopen.ui
;
import
android.content.Context
;
public
interface
FacilityView
{
public
Context
getContext
();
public
void
changeFavoriteIcon
(
boolean
favoriteStatus
);
}
app/src/main/java/srct/whatsopen/ui/activities/DetailActivity.java
View file @
bd2ad8b7
package
srct.whatsopen.ui.activities
;
import
android.content.Context
;
import
android.os.Bundle
;
import
android.support.v4.app.NavUtils
;
import
android.support.v7.app.AppCompatActivity
;
...
...
@@ -9,22 +10,16 @@ import android.view.Menu;
import
android.view.MenuItem
;
import
android.widget.TextView
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.Calendar
;
import
java.util.Date
;
import
butterknife.BindView
;
import
butterknife.ButterKnife
;
import
io.realm.Realm
;
import
io.realm.RealmList
;
import
srct.whatsopen.R
;
import
srct.whatsopen.model.Facility
;
import
srct.whatsopen.
model.OpenTimes
;
import
srct.whatsopen.ui.
adap
ters.Facility
ListAdap
ter
;
import
srct.whatsopen.
ui.FacilityView
;
import
srct.whatsopen.ui.
presen
ters.Facility
Presen
ter
;
public
class
DetailActivity
extends
AppCompatActivity
{
public
class
DetailActivity
extends
AppCompatActivity
implements
FacilityView
{
@BindView
(
R
.
id
.
open_status
)
TextView
openStatusTextView
;
@BindView
(
R
.
id
.
open_duration
)
TextView
openDurationTextView
;
...
...
@@ -33,6 +28,7 @@ public class DetailActivity extends AppCompatActivity {
MenuItem
mFavoriteMenuItem
;
private
FacilityPresenter
mPresenter
;
private
Facility
mFacility
;
@Override
...
...
@@ -42,6 +38,10 @@ public class DetailActivity extends AppCompatActivity {
getFacility
(
getIntent
().
getStringExtra
(
"name"
));
// Set up Presenter
mPresenter
=
new
FacilityPresenter
();
mPresenter
.
attachView
(
this
,
mFacility
);
// Set up layout
ButterKnife
.
bind
(
this
);
configureToolbar
();
...
...
@@ -68,7 +68,7 @@ public class DetailActivity extends AppCompatActivity {
NavUtils
.
navigateUpFromSameTask
(
this
);
return
true
;
case
R
.
id
.
miFavorite
:
toggleFavorite
Status
();
mPresenter
.
toggleFavorite
();
return
true
;
case
R
.
id
.
miOptions
:
return
true
;
...
...
@@ -77,16 +77,17 @@ public class DetailActivity extends AppCompatActivity {
}
}
// Updates the UI and Realm data for mFacility
private
void
toggleFavoriteStatus
()
{
if
(
mFacility
.
isFavorited
())
{
mFavoriteMenuItem
.
setIcon
(
R
.
drawable
.
ic_fav_button_white_24dp
);
FacilityListAdapter
.
toggleFavoriteAsync
(
this
,
mFacility
,
false
);
}
else
{
@Override
public
Context
getContext
()
{
return
this
;
}
@Override
public
void
changeFavoriteIcon
(
boolean
isFavorited
)
{
if
(
isFavorited
)
mFavoriteMenuItem
.
setIcon
(
R
.
drawable
.
ic_fav_button_on_24dp
);
FacilityListAdapter
.
toggleFavoriteAsync
(
this
,
mFacility
,
true
);
}
else
mFavoriteMenuItem
.
setIcon
(
R
.
drawable
.
ic_fav_button_white_24dp
);
}
// Queries Realm for the facility matching the key
...
...
@@ -113,119 +114,10 @@ public class DetailActivity extends AppCompatActivity {
String
statusText
=
mFacility
.
isOpen
()
?
"Open"
:
"Closed"
;
openStatusTextView
.
setText
(
statusText
);
openDurationTextView
.
setText
(
getStatusDuration
());
openDurationTextView
.
setText
(
mPresenter
.
getStatusDuration
());
locationTextView
.
setText
(
mFacility
.
getLocation
());
scheduleTextView
.
setText
(
Html
.
fromHtml
(
getSchedule
()));
}
// Finds the next time the facility closes or opens and returns it
private
String
getStatusDuration
()
{
Calendar
now
=
Calendar
.
getInstance
();
RealmList
<
OpenTimes
>
openTimesList
=
mFacility
.
getMainSchedule
().
getOpenTimesList
();
if
(
openTimesList
.
size
()
==
0
)
return
"No open time on schedule"
;
int
currentDay
=
(
5
+
now
.
get
(
Calendar
.
DAY_OF_WEEK
))
%
7
;
String
durationMessage
;
if
(
mFacility
.
isOpen
())
{
String
closingTime
=
openTimesList
.
get
(
currentDay
).
getEndTime
();
closingTime
=
parseTo12HourTime
(
closingTime
);
durationMessage
=
"Closes at "
+
closingTime
;
return
durationMessage
;
}
// Check if the facility opens later today
if
(
currentDay
<
openTimesList
.
size
())
{
SimpleDateFormat
sdf
=
new
SimpleDateFormat
(
"HH:mm:ss"
);
try
{
Date
currentTime
=
sdf
.
parse
(
sdf
.
format
(
now
.
getTime
()));
Date
startTime
=
sdf
.
parse
(
openTimesList
.
get
(
currentDay
).
getStartTime
());
if
(
currentTime
.
compareTo
(
startTime
)
<
0
)
{
String
openingTime
=
openTimesList
.
get
(
currentDay
).
getStartTime
();
openingTime
=
parseTo12HourTime
(
openingTime
);
return
"Opens today at "
+
openingTime
;
}
}
catch
(
ParseException
pe
)
{
pe
.
printStackTrace
();
return
""
;
}
}
// Else return the opening time of the next day
int
nextDay
=
(
currentDay
+
1
)
%
openTimesList
.
size
();
String
nextDayStr
=
parseIntToDay
(
nextDay
);
String
openingTime
=
openTimesList
.
get
(
nextDay
).
getStartTime
();
openingTime
=
parseTo12HourTime
(
openingTime
);
durationMessage
=
"Opens on "
+
nextDayStr
+
" at "
+
openingTime
;
return
durationMessage
;
}
// Parses 24 hour formatted time String to 12 hour formatted time String
private
String
parseTo12HourTime
(
String
time
)
{
try
{
SimpleDateFormat
sdf
=
new
SimpleDateFormat
(
"HH:mm:ss"
);
final
Date
date
=
sdf
.
parse
(
time
);
return
new
SimpleDateFormat
(
"h:mm a"
).
format
(
date
);
}
catch
(
ParseException
pe
)
{
pe
.
printStackTrace
();
return
""
;
}
}
// Parses an integer to a String of the day of the week
private
String
parseIntToDay
(
int
day
)
{
switch
(
day
)
{
case
0
:
return
"Monday"
;
case
1
:
return
"Tuesday"
;
case
2
:
return
"Wednesday"
;
case
3
:
return
"Thursday"
;
case
4
:
return
"Friday"
;
case
5
:
return
"Saturday"
;
case
6
:
return
"Sunday"
;
default
:
return
""
;
}
}
// Parses the schedule into an HTML string
private
String
getSchedule
()
{
RealmList
<
OpenTimes
>
openTimesList
=
mFacility
.
getMainSchedule
().
getOpenTimesList
();
if
(
openTimesList
.
size
()
==
0
)
return
"No schedule available"
;
StringBuilder
scheduleString
=
new
StringBuilder
();
boolean
first
=
true
;
for
(
OpenTimes
o
:
openTimesList
)
{
if
(
first
)
first
=
false
;
else
scheduleString
.
append
(
"<br/>"
);
scheduleString
.
append
(
"<b>"
+
parseIntToDay
(
o
.
getStartDay
())
+
"</b>: "
);
scheduleString
.
append
(
parseTo12HourTime
(
o
.
getStartTime
()));
scheduleString
.
append
(
" - "
);
scheduleString
.
append
(
parseTo12HourTime
(
o
.
getEndTime
()));
}
return
scheduleString
.
toString
();
scheduleTextView
.
setText
(
Html
.
fromHtml
(
mPresenter
.
getSchedule
()));
}
}
app/src/main/java/srct/whatsopen/ui/activities/MainActivity.java
View file @
bd2ad8b7
package
srct.whatsopen.ui.activities
;
import
android.content.SharedPreferences
;
import
android.preference.PreferenceManager
;
import
android.support.v4.app.Fragment
;
import
android.support.v4.app.FragmentTransaction
;
import
android.support.v4.view.ViewPager
;
import
android.support.v7.app.AppCompatActivity
;
import
android.os.Bundle
;
import
android.support.v7.widget.RecyclerView
;
import
android.support.v7.widget.Toolbar
;
import
android.view.Menu
;
import
com.astuetz.PagerSlidingTabStrip
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.Calendar
;
import
java.util.Date
;
import
java.util.List
;
import
butterknife.ButterKnife
;
import
io.realm.Realm
;
import
io.realm.RealmList
;
import
retrofit2.Call
;
import
retrofit2.Callback
;
import
retrofit2.Response
;
import
srct.whatsopen.R
;
import
srct.whatsopen.model.OpenTimes
;
import
srct.whatsopen.service.WhatsOpenClient
;
import
srct.whatsopen.service.WhatsOpenService
;
import
srct.whatsopen.model.Facility
;
import
srct.whatsopen.ui.presenters.MainPresenter
;
import
srct.whatsopen.ui.adapters.FacilityListFragmentPagerAdapter
;
public
class
MainActivity
extends
AppCompatActivity
{
private
RecyclerView
mRecyclerView
;
private
MainPresenter
mPresenter
;
@Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setContentView
(
R
.
layout
.
activity_main
);
// Set up presenter
mPresenter
=
new
MainPresenter
();
mPresenter
.
attachView
(
this
);
// Get facility data
mPresenter
.
loadFacilities
();
// Configure toolbar
Toolbar
toolbar
=
ButterKnife
.
findById
(
this
,
R
.
id
.
toolbar
);
setSupportActionBar
(
toolbar
);
// Get WhatsOpenClient singleton
WhatsOpenService
service
=
WhatsOpenClient
.
getInstance
();
callWhatsOpenAPI
(
service
);
// Get the ViewPager and set its PagerAdapter
ViewPager
viewPager
=
ButterKnife
.
findById
(
this
,
R
.
id
.
view_pager
);
viewPager
.
setAdapter
(
new
FacilityListFragmentPagerAdapter
(
getSupportFragmentManager
()));
...
...
@@ -64,94 +46,15 @@ public class MainActivity extends AppCompatActivity {
viewPager
.
setCurrentItem
(
1
);
}
@Override
protected
void
onDestroy
()
{
mPresenter
.
detachView
();
super
.
onDestroy
();
}
@Override
public
boolean
onCreateOptionsMenu
(
Menu
menu
)
{
getMenuInflater
().
inflate
(
R
.
menu
.
menu_main
,
menu
);
return
true
;
}
// does not work currently
/*
private void setDefaultTab(ViewPager viewPager) {
RealmResults<Facility> results = mRealm.where(Facility.class).equalTo("isFavorited", true)
.findAllAsync();
if(results.size() == 0)
viewPager.setCurrentItem(1);
else
viewPager.setCurrentItem(0);
}
*/
// Gets a Call from the given Retrofit service, then asynchronously executes it
// On success, copies the resulting facility list to the Realm DB
private
void
callWhatsOpenAPI
(
WhatsOpenService
service
)
{
// Get Realm and SharedPreference instances
final
Realm
realm
=
Realm
.
getDefaultInstance
();
final
SharedPreferences
pref
=
PreferenceManager
.
getDefaultSharedPreferences
(
this
);
Call
<
List
<
Facility
>>
call
=
service
.
facilityList
();
call
.
enqueue
(
new
Callback
<
List
<
Facility
>>()
{
@Override
public
void
onResponse
(
Call
<
List
<
Facility
>>
call
,
Response
<
List
<
Facility
>>
response
)
{
List
<
Facility
>
facilities
=
response
.
body
();
for
(
Facility
facility
:
facilities
)
{
// Query SharedReferences for each Facility's favorite status. defaults to false
facility
.
setFavorited
(
pref
.
getBoolean
(
facility
.
getName
(),
false
));
facility
.
setOpen
(
getOpenStatus
(
facility
));
}
realm
.
beginTransaction
();
realm
.
copyToRealmOrUpdate
(
facilities
);
realm
.
commitTransaction
();
realm
.
close
();
}
@Override
public
void
onFailure
(
Call
<
List
<
Facility
>>
call
,
Throwable
t
)
{
// do some stuff
realm
.
close
();
}
});
}
// Uses the device time to determine which facilities should be open
private
boolean
getOpenStatus
(
Facility
facility
)
{
Calendar
now
=
Calendar
.
getInstance
();
RealmList
<
OpenTimes
>
openTimesList
=
facility
.
getMainSchedule
().
getOpenTimesList
();
// have to mess with the current day value, as Calender.DAY_OF_WEEK
// starts with Sunday as 1 and the Whats Open Api starts with Monday at 0
int
currentDay
=
(
5
+
now
.
get
(
Calendar
.
DAY_OF_WEEK
))
%
7
;
OpenTimes
currentOpenTimes
=
null
;
for
(
OpenTimes
o
:
openTimesList
)
{
if
(
o
.
getStartDay
()
==
currentDay
||
o
.
getEndDay
()
==
currentDay
)
currentOpenTimes
=
o
;
}
if
(
currentOpenTimes
==
null
)
return
false
;
SimpleDateFormat
sdf
=
new
SimpleDateFormat
(
"HH:mm:ss"
);
try
{
Date
startTime
=
sdf
.
parse
(
currentOpenTimes
.
getStartTime
());
Date
endTime
=
sdf
.
parse
(
currentOpenTimes
.
getEndTime
());
// have to parse it from date to string to date. how fun
Date
currentTime
=
sdf
.
parse
(
sdf
.
format
(
now
.
getTime
()));
if
(
currentTime
.
compareTo
(
startTime
)
>
0
&&
currentTime
.
compareTo
(
endTime
)
<
0
)
return
true
;
else
return
false
;
}
catch
(
ParseException
pe
)
{
pe
.
printStackTrace
();
return
false
;
}
}
}
app/src/main/java/srct/whatsopen/ui/adapters/FacilityListAdapter.java
View file @
bd2ad8b7
...
...
@@ -3,8 +3,6 @@ package srct.whatsopen.ui.adapters;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.SharedPreferences
;
import
android.preference.PreferenceManager
;
import
android.support.v4.content.ContextCompat
;
import
android.support.v7.widget.RecyclerView
;
import
android.view.LayoutInflater
;
...
...
@@ -18,11 +16,12 @@ import butterknife.ButterKnife;
import
butterknife.OnClick
;
import
io.realm.OrderedRealmCollection
;
import
io.realm.Realm
;
import
io.realm.RealmRecyclerViewAdapter
;
import
srct.whatsopen.R
;
import
srct.whatsopen.model.Facility
;
import
srct.whatsopen.ui.FacilityView
;
import
srct.whatsopen.ui.activities.DetailActivity
;
import
srct.whatsopen.ui.presenters.FacilityPresenter
;
/**
* Basic RecyclerView boilerplate, with some added Realm stuff
...
...
@@ -68,74 +67,61 @@ public class FacilityListAdapter extends
holder
.
favoriteButton
.
setImageResource
(
R
.
drawable
.
ic_fav_button_off_24dp
);
}
holder
.
data
=
facility
;
holder
.
setData
(
facility
)
;
TextView
textView
=
holder
.
nameTextView
;
textView
.
setText
(
facility
.
getName
());
}
// Asynchronously updates the Realm object's favorite status
// and updates the favorite status in SharedPreferences
// Would block the favorite button redrawing if done on the UI thread
public
static
void
toggleFavoriteAsync
(
Context
context
,
Facility
facility
,
final
boolean
status
)
{
Realm
realm
=
Realm
.
getDefaultInstance
();
SharedPreferences
pref
=
PreferenceManager
.
getDefaultSharedPreferences
(
context
);
final
SharedPreferences
.
Editor
editor
=
pref
.
edit
();
final
String
facilityName
=
facility
.
getName
();
realm
.
executeTransactionAsync
(
new
Realm
.
Transaction
()
{
@Override
public
void
execute
(
Realm
bgRealm
)
{
// have to requery for the object as it was created on a separate thread
Facility
facility
=
bgRealm
.
where
(
Facility
.
class
)
.
equalTo
(
"mName"
,
facilityName
).
findFirst
();
facility
.
setFavorited
(
status
);
editor
.
putBoolean
(
facilityName
,
status
);
editor
.
apply
();
}
},
null
,
null
);
realm
.
close
();
}
// Set up for the Recycler View cells
public
class
ViewHolder
extends
RecyclerView
.
ViewHolder
{
public
class
ViewHolder
extends
RecyclerView
.
ViewHolder
implements
FacilityView
{
@BindView
(
R
.
id
.
facility_name
)
TextView
nameTextView
;
@BindView
(
R
.
id
.
favorite_button
)
ImageButton
favoriteButton
;
public
Facility
data
;
FacilityPresenter
mPresenter
;
Facility
data
;
public
ViewHolder
(
final
View
itemView
)
{
super
(
itemView
);
ButterKnife
.
bind
(
this
,
itemView
);
}
public
void
setData
(
Facility
facility
)
{
data
=
facility
;
// Set up presenter
mPresenter
=
new
FacilityPresenter
();
mPresenter
.
attachView
(
this
,
data
);
}
// transitions to the facility's detail view
@OnClick
(
R
.
id
.
text_layout
)
public
void
expandFacilityView
()
{
Intent
i
=
new
Intent
(
context
,
DetailActivity
.
class
);
i
.
putExtra
(
"name"
,
data
.
getName
());
Intent
i
ntent
=
new
Intent
(
context
,
DetailActivity
.
class
);
i
ntent
.
putExtra
(
"name"
,
data
.
getName
());
context
.
startActivity
(
i
);
context
.
startActivity
(
i
ntent
);
}
// toggles favorite status
@OnClick
(
R
.
id
.
favorite_button
)
public
void
setFavorite
(
ImageButton
favoriteButton
)
{
if
(
data
.
isFavorited
())
{
public
void
setFavorite
()
{
mPresenter
.
toggleFavorite
();
}
@Override
public
void
changeFavoriteIcon
(
boolean
isFavorited
)
{
if
(
isFavorited
)
favoriteButton
.
setImageResource
(
R
.
drawable
.
ic_fav_button_off_24dp
);
toggleFavoriteAsync
(
context
,
data
,
false
);
}
else
{
else
favoriteButton
.
setImageResource
(
R
.
drawable
.
ic_fav_button_on_24dp
);
toggleFavoriteAsync
(
context
,
data
,
true
);
}
}
@Override
public
Context
getContext
()
{
return
context
;
}
}
}
app/src/main/java/srct/whatsopen/ui/DividerItemDecoration.java
→
app/src/main/java/srct/whatsopen/ui/
decorations/
DividerItemDecoration.java
View file @
bd2ad8b7
package
srct.whatsopen.ui
;
import
android.graphics.Canvas
;
import
android.graphics.Rect
;
import
android.graphics.drawable.Drawable
;
import
android.support.v7.widget.RecyclerView
;
import
android.view.View
;
/**
* Used for creating the dividers in the Recycler View
*/
public
class
DividerItemDecoration
extends
RecyclerView
.
ItemDecoration
{
private
Drawable
mDivider
;
public
DividerItemDecoration
(
Drawable
divider
)
{
mDivider
=
divider
;
}
@Override
public
void
getItemOffsets
(
Rect
outRect
,
View
view
,
RecyclerView
parent
,
RecyclerView
.
State
state
)
{
super
.
getItemOffsets
(
outRect
,
view
,
parent
,
state
);
if
(
parent
.
getChildAdapterPosition
(
view
)
==
0
)
{
return
;
}
outRect
.
top
=
mDivider
.
getIntrinsicHeight
();
}
@Override
public
void
onDraw
(
Canvas
canvas
,
RecyclerView
parent
,
RecyclerView
.
State
state
)
{
int
dividerLeft
=
parent
.
getPaddingLeft
();
int
dividerRight
=
parent
.
getWidth
()
-
parent
.
getPaddingRight
();
int
childCount
=
parent
.
getChildCount
();
for
(
int
i
=
0
;
i
<
childCount
-
1
;
i
++)
{
View
child
=
parent
.
getChildAt
(
i
);
RecyclerView
.
LayoutParams
params
=
(
RecyclerView
.
LayoutParams
)
child
.
getLayoutParams
();
int
dividerTop
=
child
.
getBottom
()
+
params
.
bottomMargin
;
int
dividerBottom
=
dividerTop
+
mDivider
.
getIntrinsicHeight
();
mDivider
.
setBounds
(
dividerLeft
,
dividerTop
,
dividerRight
,
dividerBottom
);
mDivider
.
draw
(
canvas
);
}
}
}
package
srct.whatsopen.ui
.decorations
;
import
android.graphics.Canvas
;
import
android.graphics.Rect
;
import
android.graphics.drawable.Drawable
;
import
android.support.v7.widget.RecyclerView
;
import
android.view.View
;
/**
* Used for creating the dividers in the Recycler View
*/
public
class
DividerItemDecoration
extends
RecyclerView
.
ItemDecoration
{