-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
392 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
PennMobile/src/main/java/com/pennapps/labs/pennmobile/api/GsrReservationsRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.pennapps.labs.pennmobile.api; | ||
|
||
import com.pennapps.labs.pennmobile.gsr.classes.GSRReservation; | ||
|
||
import java.util.List; | ||
|
||
import retrofit.http.GET; | ||
import retrofit.http.Header; | ||
import rx.Observable; | ||
|
||
public interface GsrReservationsRequest { | ||
@GET("/gsr/reservations") | ||
Observable<List<GSRReservation>> getGsrReservations( | ||
@Header("Authorization") String bearerToken | ||
); | ||
} |
119 changes: 119 additions & 0 deletions
119
PennMobile/src/main/java/com/pennapps/labs/pennmobile/gsr/widget/GsrReservationsWidget.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package com.pennapps.labs.pennmobile.gsr.widget | ||
|
||
import android.app.PendingIntent | ||
import android.appwidget.AppWidgetManager | ||
import android.appwidget.AppWidgetProvider | ||
import android.content.Context | ||
import android.content.Intent | ||
import android.net.Uri | ||
import android.widget.RemoteViews | ||
import com.google.gson.GsonBuilder | ||
import com.google.gson.reflect.TypeToken | ||
import com.pennapps.labs.pennmobile.MainActivity | ||
import com.pennapps.labs.pennmobile.R | ||
import com.pennapps.labs.pennmobile.api.GsrReservationsRequest | ||
import com.pennapps.labs.pennmobile.api.Serializer | ||
import com.pennapps.labs.pennmobile.gsr.classes.GSRReservation | ||
import com.squareup.okhttp.OkHttpClient | ||
import retrofit.RestAdapter | ||
import retrofit.client.OkClient | ||
import retrofit.converter.GsonConverter | ||
import java.util.concurrent.TimeUnit | ||
|
||
class GsrReservationsWidget : AppWidgetProvider() { | ||
override fun onUpdate( | ||
context: Context, | ||
appWidgetManager: AppWidgetManager, | ||
appWidgetIds: IntArray, | ||
) { | ||
for (appWidgetId in appWidgetIds) { | ||
val mainActivityIntent = Intent(context, MainActivity::class.java) | ||
mainActivityIntent.apply { | ||
flags += Intent.FLAG_ACTIVITY_NEW_TASK | ||
flags += Intent.FLAG_ACTIVITY_CLEAR_TOP | ||
} | ||
|
||
mainActivityIntent.putExtra("Gsr_Tab_Switch", 1) | ||
|
||
val serviceIntent = Intent(context, GsrReservationsWidgetAdapter::class.java) | ||
val pendingIntent: PendingIntent = | ||
PendingIntent.getActivity( | ||
context, | ||
appWidgetId, | ||
mainActivityIntent, | ||
PendingIntent.FLAG_IMMUTABLE, | ||
) | ||
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) | ||
|
||
// setData allows the system to distinguish between different service intents. Without | ||
// setData, onGetViewFactory is called only once for multiple widgets and send | ||
// the same intent to all of them. | ||
serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))) | ||
|
||
// Setting up the widget remoteViews; change cardview to something else | ||
val views = RemoteViews(context.packageName, R.layout.gsr_reservations_widget) | ||
views.setRemoteAdapter(R.id.gsr_reservation_widget_stack_view, serviceIntent) | ||
views.setEmptyView( | ||
R.id.gsr_reservation_widget_stack_view, | ||
R.id.gsr_reservation_widget_empty_view, | ||
) | ||
|
||
// Setting up the intents for the remoteview for both when it is empty and | ||
// when it loads the collection view (in this case we use setPendingIntentTemplate to | ||
// the entire stackView that contains all the items). | ||
views.setPendingIntentTemplate(R.id.gsr_reservation_widget_stack_view, pendingIntent) | ||
views.setOnClickPendingIntent(R.id.gsr_reservation_widget_empty_view, pendingIntent) | ||
|
||
// Notify appwidgetviewdata has changed to call getViewAt to set up the widget UI | ||
// and handle update for every appwidget item in the Collection widget. | ||
appWidgetManager.notifyAppWidgetViewDataChanged( | ||
appWidgetId, | ||
R.id.gsr_reservation_widget_stack_view, | ||
) | ||
appWidgetManager.updateAppWidget(appWidgetId, views) | ||
} | ||
} | ||
|
||
// onEnabled and onDisabled are typically used for alarmManager testing and logs to check whether | ||
// appwidget is properly enabled/disabled. | ||
override fun onEnabled(context: Context) { | ||
} | ||
|
||
override fun onDisabled(context: Context) { | ||
} | ||
|
||
companion object { | ||
private var mGSRReservationsRequest: GsrReservationsRequest? = null | ||
|
||
@JvmStatic | ||
val gsrReservationsRequestInstance: GsrReservationsRequest | ||
get() { | ||
if (mGSRReservationsRequest == null) { | ||
val gsonBuilder = GsonBuilder() | ||
|
||
// RegisterTypeAdapter with GsrReservationSerializer | ||
// since we are only accessing gsr reservations | ||
gsonBuilder.registerTypeAdapter( | ||
object : TypeToken<MutableList<GSRReservation?>?>() {}.type, | ||
Serializer.GsrReservationSerializer(), | ||
) | ||
|
||
val gson = gsonBuilder.create() | ||
val okHttpClient = OkHttpClient() | ||
okHttpClient.setConnectTimeout(35, TimeUnit.SECONDS) // Connection timeout | ||
okHttpClient.setReadTimeout(35, TimeUnit.SECONDS) // Read timeout | ||
okHttpClient.setWriteTimeout(35, TimeUnit.SECONDS) // Write timeout | ||
|
||
val restAdapter = | ||
RestAdapter | ||
.Builder() | ||
.setConverter(GsonConverter(gson)) | ||
.setClient(OkClient(okHttpClient)) | ||
.setEndpoint("https://pennmobile.org/api") | ||
.build() | ||
mGSRReservationsRequest = restAdapter.create(GsrReservationsRequest::class.java) | ||
} | ||
return mGSRReservationsRequest!! | ||
} | ||
} | ||
} |
136 changes: 136 additions & 0 deletions
136
...ile/src/main/java/com/pennapps/labs/pennmobile/gsr/widget/GsrReservationsWidgetAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package com.pennapps.labs.pennmobile.gsr.widget | ||
|
||
import android.appwidget.AppWidgetManager | ||
import android.content.Context | ||
import android.content.Intent | ||
import android.graphics.BitmapFactory | ||
import android.os.Bundle | ||
import android.widget.RemoteViews | ||
import android.widget.RemoteViewsService | ||
import androidx.preference.PreferenceManager | ||
import com.google.firebase.crashlytics.FirebaseCrashlytics | ||
import com.pennapps.labs.pennmobile.R | ||
import com.pennapps.labs.pennmobile.api.GsrReservationsRequest | ||
import com.pennapps.labs.pennmobile.gsr.classes.GSRReservation | ||
import org.joda.time.format.DateTimeFormat | ||
import org.joda.time.format.DateTimeFormatter | ||
import rx.Observable | ||
import java.net.HttpURLConnection | ||
import java.net.URL | ||
|
||
class GsrReservationsWidgetAdapter : RemoteViewsService() { | ||
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory = GsrReservationWidgetFactory(applicationContext, intent) | ||
|
||
class GsrReservationWidgetFactory( | ||
private val context: Context, | ||
intent: Intent, | ||
) : RemoteViewsFactory { | ||
private var mGsrReservationsRequest: GsrReservationsRequest? = null | ||
private var appWidgetId: Int = | ||
intent.getIntExtra( | ||
AppWidgetManager.EXTRA_APPWIDGET_ID, | ||
AppWidgetManager.INVALID_APPWIDGET_ID, | ||
) | ||
private var dataSet: List<GSRReservation> = emptyList() | ||
private var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) | ||
|
||
override fun onCreate() { | ||
mGsrReservationsRequest = GsrReservationsWidget.gsrReservationsRequestInstance | ||
getWidgetGsrReservations() | ||
} | ||
|
||
// Not used since already handled | ||
override fun onDataSetChanged() { | ||
} | ||
|
||
override fun onDestroy() { | ||
} | ||
|
||
override fun getCount(): Int = dataSet.size | ||
|
||
// TODO("Get building name(?), and hopefully support click behavior") | ||
override fun getViewAt(index: Int): RemoteViews { | ||
val reservation = dataSet[index] | ||
val roomName = reservation.name | ||
|
||
val formatter: DateTimeFormatter = | ||
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ") | ||
val from = formatter.parseDateTime(reservation.fromDate) | ||
val to = formatter.parseDateTime(reservation.toDate) | ||
val day = from.toString("EEEE, MMMM d") | ||
val fromHour = from.toString("h:mm a") | ||
val toHour = to.toString("h:mm a") | ||
|
||
val imageUrl = | ||
reservation.info?.get("thumbnail") | ||
?: "https://s3.us-east-2.amazonaws.com/labs.api/dining/MBA+Cafe.jpg" | ||
|
||
val views = RemoteViews(context.packageName, R.layout.gsr_reservations_widget_item) | ||
views.setTextViewText(R.id.gsr_reservation_widget_item_location_tv, roomName) | ||
views.setTextViewText( | ||
R.id.gsr_reservation_widget_item_time_tv, | ||
"$day\n$fromHour-$toHour", | ||
) | ||
|
||
try { | ||
val urlConnection = URL(imageUrl) | ||
val connection = | ||
urlConnection | ||
.openConnection() as HttpURLConnection | ||
connection.doInput = true | ||
connection.connect() | ||
val input = connection.inputStream | ||
val myBitmap = BitmapFactory.decodeStream(input) | ||
views.setImageViewBitmap(R.id.gsr_reservation_widget_item_iv, myBitmap) | ||
} catch (e: Exception) { | ||
e.printStackTrace() | ||
} | ||
|
||
val extras = Bundle() | ||
val fillInIntent = Intent() | ||
fillInIntent.putExtras(extras) | ||
views.setOnClickFillInIntent(R.id.gsr_reservation_widget_item_root, fillInIntent) | ||
|
||
return views | ||
} | ||
|
||
override fun getLoadingView(): RemoteViews? = null | ||
|
||
override fun getViewTypeCount(): Int = 1 | ||
|
||
override fun getItemId(id: Int): Long = id.toLong() | ||
|
||
override fun hasStableIds(): Boolean = true | ||
|
||
private fun getWidgetGsrReservations() { | ||
try { | ||
if (mGsrReservationsRequest != null) { | ||
val token = | ||
sharedPreferences.getString( | ||
context.getString(R.string.access_token), | ||
"", | ||
) | ||
mGsrReservationsRequest!! | ||
.getGsrReservations("Bearer $token") | ||
.flatMap { reservations -> Observable.from(reservations) } | ||
.flatMap { reservation -> | ||
Observable.just(reservation) | ||
}.toList() | ||
.subscribe { reservations -> | ||
dataSet = reservations | ||
println("subscribed") | ||
val appWidgetManager: AppWidgetManager = | ||
AppWidgetManager.getInstance(context) | ||
appWidgetManager.notifyAppWidgetViewDataChanged( | ||
appWidgetId, | ||
R.id.gsr_reservation_widget_stack_view, | ||
) | ||
} | ||
} | ||
} catch (e: Exception) { | ||
FirebaseCrashlytics.getInstance().recordException(e) | ||
e.printStackTrace() | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
PennMobile/src/main/res/layout/gsr_reservations_widget.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:orientation="horizontal" | ||
android:theme="@style/Theme.Pennmobileandroid.AppWidgetContainer" | ||
android:id="@+id/gsr_reservation_widget_root" > | ||
<FrameLayout | ||
android:id="@+id/widgetframe" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:theme="@style/Theme.Pennmobileandroid.AppWidgetContainer" | ||
> | ||
<ListView | ||
android:id="@+id/gsr_reservation_widget_stack_view" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:loopViews="true" | ||
android:divider="@android:color/transparent" | ||
android:dividerHeight="8dp" | ||
/> | ||
|
||
<ImageView | ||
android:contentDescription="Penn Logo" | ||
android:id="@+id/gsr_reservation_widget_empty_view" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:layout_gravity="center" | ||
android:background="@drawable/app_widget_background" | ||
android:scaleType="centerCrop" | ||
android:src="@drawable/splash_screen435" | ||
/> | ||
</FrameLayout> | ||
</LinearLayout> |
Oops, something went wrong.