From a7770af562eaedf2fb2e175a6a6dfd36b4a8d7c7 Mon Sep 17 00:00:00 2001 From: EricKarschner37 Date: Mon, 30 Sep 2019 11:39:55 -0400 Subject: [PATCH 01/10] Begin work on SignInAPI --- .idea/misc.xml | 8 +- app/build.gradle | 46 ++-- .../bettervent/ExampleInstrumentedTest.java | 5 +- app/src/main/AndroidManifest.xml | 22 +- .../edu/rit/csh/bettervent/ApiAsyncTask.kt | 2 +- .../edu/rit/csh/bettervent/MainActivity.kt | 218 ++++++--------- .../csh/bettervent/MainActivityViewModel.kt | 28 ++ .../csh/bettervent/ParticipantListAdapter.kt | 2 +- .../rit/csh/bettervent/QuickModeFragment.kt | 28 +- .../rit/csh/bettervent/ScheduleFragment.kt | 2 +- .../rit/csh/bettervent/SettingsFragment.kt | 2 +- .../edu/rit/csh/bettervent/StatusFragment.kt | 259 +++++------------- app/src/main/res/layout/activity_main.xml | 17 +- .../main/res/layout/activity_main_loading.xml | 11 + .../main/res/layout/fragment_quick_mode.xml | 11 +- app/src/main/res/layout/fragment_schedule.xml | 4 +- gradle.properties | 2 + 17 files changed, 281 insertions(+), 386 deletions(-) create mode 100644 app/src/main/java/edu/rit/csh/bettervent/MainActivityViewModel.kt create mode 100644 app/src/main/res/layout/activity_main_loading.xml diff --git a/.idea/misc.xml b/.idea/misc.xml index 51fa3e5..d04819c 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,7 +5,7 @@ diff --git a/app/build.gradle b/app/build.gradle index e55aba0..a0559b9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,16 +1,17 @@ apply plugin: 'com.android.application' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { applicationId "edu.rit.csh.bettervent" - minSdkVersion 23 - targetSdkVersion 28 + minSdkVersion 26 + targetSdkVersion 29 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true multiDexEnabled true } @@ -22,27 +23,33 @@ android { } } + dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:28.0.0' - implementation 'com.android.support:design:28.0.0' - implementation 'com.android.support:support-vector-drawable:28.0.0' + implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0' + implementation 'androidx.recyclerview:recyclerview:1.0.0' + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.vectordrawable:vectordrawable:1.1.0' implementation 'org.jetbrains.anko:anko-commons:0.10.8' implementation 'org.jetbrains.anko:anko-design:0.10.8' testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - implementation 'com.android.support.constraint:constraint-layout:1.1.3' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' // Google Calendar API dependencies - implementation 'com.google.android.gms:play-services:12.0.1' - api 'com.google.apis:google-api-services-calendar:v3-rev119-1.19.1' - api 'com.google.api-client:google-api-client:1.23.0' - api 'com.google.api-client:google-api-client-android:1.23.0' - api 'com.google.api-client:google-api-client-gson:1.19.1' - + implementation 'com.google.api-client:google-api-client:1.23.0' + implementation 'com.google.oauth-client:google-oauth-client-jetty:1.23.0' + implementation 'com.google.apis:google-api-services-calendar:v3-rev305-1.23.0' + implementation 'com.google.android.gms:play-services-base:17.1.0' implementation 'com.github.thellmund:Android-Week-View:3.1.3' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.google.android.gms:play-services-auth:17.0.0' + implementation 'com.google.api-client:google-api-client:1.23.0' + implementation 'com.google.api-client:google-api-client-android:1.23.0' + implementation 'com.google.apis:google-api-services-people:v1-rev4-1.22.0' + implementation 'com.google.http-client:google-http-client-gson:1.19.0' } configurations { @@ -52,4 +59,7 @@ configurations { } repositories { mavenCentral() -} \ No newline at end of file +} +androidExtensions { + experimental = true +} diff --git a/app/src/androidTest/java/edu/rit/csh/bettervent/ExampleInstrumentedTest.java b/app/src/androidTest/java/edu/rit/csh/bettervent/ExampleInstrumentedTest.java index 13a8454..dbada70 100644 --- a/app/src/androidTest/java/edu/rit/csh/bettervent/ExampleInstrumentedTest.java +++ b/app/src/androidTest/java/edu/rit/csh/bettervent/ExampleInstrumentedTest.java @@ -1,8 +1,9 @@ package edu.rit.csh.bettervent; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4fb2e6f..2f4bac8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,13 +2,14 @@ + - - @@ -20,23 +21,30 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Design.Light.NoActionBar"> - + + - + + - + diff --git a/app/src/main/java/edu/rit/csh/bettervent/ApiAsyncTask.kt b/app/src/main/java/edu/rit/csh/bettervent/ApiAsyncTask.kt index b600073..9e12a36 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/ApiAsyncTask.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/ApiAsyncTask.kt @@ -74,7 +74,7 @@ internal constructor(private val mainActivity: MainActivity) : AsyncTask() } } \ No newline at end of file diff --git a/app/src/main/java/edu/rit/csh/bettervent/MainActivity.kt b/app/src/main/java/edu/rit/csh/bettervent/MainActivity.kt index 1616bfc..3e5e11d 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/MainActivity.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/MainActivity.kt @@ -3,50 +3,62 @@ package edu.rit.csh.bettervent import android.accounts.Account import android.app.admin.DevicePolicyManager import android.content.ComponentName -import android.support.design.widget.BottomNavigationView -import android.support.design.widget.FloatingActionButton -import android.support.v4.app.Fragment -import android.support.v7.app.AppCompatActivity +import com.google.android.material.floatingactionbutton.FloatingActionButton +import androidx.fragment.app.Fragment +import androidx.appcompat.app.AppCompatActivity import android.os.Bundle -import android.view.MenuItem import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential import android.accounts.AccountManager import android.app.Activity -import android.app.Dialog +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.net.ConnectivityManager -import android.net.NetworkInfo import android.os.Handler -import android.view.View +import android.os.Parcelable +import android.util.Log +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter import android.widget.TextClock import android.widget.Toast +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInAccount +import com.google.android.gms.auth.api.signin.GoogleSignInOptions import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GooglePlayServicesUtil +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.tasks.Task import com.google.api.client.extensions.android.http.AndroidHttp -import com.google.api.client.http.HttpTransport import com.google.api.client.json.JsonFactory import com.google.api.client.json.gson.GsonFactory import com.google.api.client.util.DateTime import com.google.api.client.util.ExponentialBackOff import com.google.api.services.calendar.CalendarScopes -import com.google.api.services.calendar.model.* - -import java.lang.reflect.Array -import java.util.ArrayList -import java.util.Arrays - -class MainActivity : AppCompatActivity() { +import kotlinx.android.parcel.Parcelize +import kotlinx.android.synthetic.main.activity_main.* +import java.text.SimpleDateFormat +import java.util.* + +class MainActivity : AppCompatActivity(), OpenSettingsListener { + override fun openSettings() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } internal lateinit var mService: com.google.api.services.calendar.Calendar internal lateinit var credential: GoogleAccountCredential // This MainActivity gets the data from the API, and holds it // as a list. The Fragments then update themselves using that. + private lateinit var model: MainActivityViewModel + private lateinit var statusFragment: StatusFragment + private lateinit var scheduleFragment: ScheduleFragment + private lateinit var quickModeFragment: QuickModeFragment + private val APIOutList = ArrayList() internal val transport = AndroidHttp.newCompatibleTransport() internal val jsonFactory: JsonFactory = GsonFactory.getDefaultInstance() @@ -57,25 +69,12 @@ class MainActivity : AppCompatActivity() { private lateinit var APIStatusMessage: String var isReserved = true - private lateinit var bottomNav: BottomNavigationView private lateinit var refreshButton: FloatingActionButton - private val navListener = BottomNavigationView.OnNavigationItemSelectedListener { item -> - selectedFragment = null - when (item.itemId) { - R.id.navigation_status -> - // selectedFragment = new StatusFragment(); - selectedFragment = StatusFragment.newInstance(APIOutList) - R.id.navigation_schedule -> selectedFragment = ScheduleFragment.newInstance(APIOutList) - R.id.navigation_quick_mode -> selectedFragment = QuickModeFragment() - } - - // System.out.println("*** currentEventTitle: " + currentEventTitle); - supportFragmentManager.beginTransaction().replace(R.id.fragment_container, - selectedFragment!!).commit() - - true - } + private lateinit var fragments: List + private lateinit var account: GoogleSignInAccount + private lateinit var mGoogleSignInClient: GoogleSignInAccount + private lateinit var gso: GoogleSignInOptions /** * Checks whether the device currently has a network connection. @@ -108,6 +107,8 @@ class MainActivity : AppCompatActivity() { } + + /** * Checks the times of the first event in APIOutList (the List of Events generated by the API) * and if the current time is within those times, then the room is booked @@ -115,31 +116,20 @@ class MainActivity : AppCompatActivity() { * @return: true if the current time is outside of the time of the * next event, and false if vice-versa. */ - private// Then the room is currently in use. - // If something weird happens, just assume the room is free. - val isFree: Boolean - get() { - try { - val now = DateTime(System.currentTimeMillis()) - val firstEventStart = APIOutList[0].start.dateTime - val firstEventEnd = APIOutList[0].end.dateTime - if (now.value > firstEventStart.value && now.value < firstEventEnd.value) { - isReserved = true - return false - } else { - isReserved = false - return true - } - } catch (e: Exception) { - isReserved = false - return true - } - } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + setContentView(R.layout.activity_main_loading) + + gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .build() + + model = ViewModelProviders.of(this)[MainActivityViewModel::class.java] + model.getEvents().observe(this, Observer> { events -> + setupMainView(events) + }) // Load up app settings to fetch passwords and background colors. @@ -174,55 +164,32 @@ class MainActivity : AppCompatActivity() { startLockTask() + // Initialize credentials and service object. + val settings = getPreferences(Context.MODE_PRIVATE) + - bottomNav = findViewById(R.id.bottom_navigation) - bottomNav.setOnNavigationItemSelectedListener(navListener) + refreshResults() - refreshButton = findViewById(R.id.refresh_button) + } + + private fun setupMainView(events: ArrayList){ + refreshButton = findViewById(R.id.refresh_button) refreshButton.setOnClickListener { // TODO: figure out why you have to do this twice to make anything happen. refreshResults() - refreshUI() - } - - // Initialize credentials and service object. - val settings = getPreferences(Context.MODE_PRIVATE) - credential = GoogleAccountCredential.usingOAuth2( - applicationContext, Arrays.asList(*SCOPES)) - .setBackOff(ExponentialBackOff()) - .setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null)) - - mService = com.google.api.services.calendar.Calendar.Builder( - transport, jsonFactory, credential) - .setApplicationName("Google Calendar API Android Quickstart") - .build() - - refreshResults() - if (selectedFragment == null) { - selectedFragment = StatusFragment.newInstance(APIOutList) - supportFragmentManager.beginTransaction().replace(R.id.fragment_container, - selectedFragment!!).commit() } + pager.adapter = SlidingPagerAdapter(supportFragmentManager) centralClock = findViewById(R.id.central_clock) - // Initialize API Refresher. Make sure to sign into a google account before launching the app. - val handler = Handler() - val runnable = object : Runnable { - override fun run() { - if (credential.selectedAccountName != null) { - refreshResults() - println(" *** Refreshed.") - refreshUI() - handler.postDelayed(this, 10000) - } - } - } - - //Start API Refresher - handler.postDelayed(runnable, 1000) - + val bundle = Bundle() + bundle.putParcelableArrayList("events", events) + statusFragment = StatusFragment() + statusFragment.arguments = bundle + scheduleFragment = ScheduleFragment() + quickModeFragment = QuickModeFragment() + fragments = listOf(statusFragment, scheduleFragment, quickModeFragment) } /** @@ -265,17 +232,15 @@ class MainActivity : AppCompatActivity() { infoPrint("Result = $resultCode") val accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME) infoPrint("Account name = " + accountName!!) - if (accountName != null) { - // credential.setSelectedAccountName(accountName); - credential.selectedAccount = Account(accountName, "edu.rit.csh.bettervent") - infoPrint("Account name set. Account name = $accountName") - infoPrint(credential.selectedAccountName) - val settings = getPreferences(Context.MODE_PRIVATE) - val editor = settings.edit() - editor.putString(PREF_ACCOUNT_NAME, accountName) - editor.commit() - refreshResults() - } + // credential.setSelectedAccountName(accountName); + credential.selectedAccount = Account(accountName, "edu.rit.csh.bettervent") + infoPrint("Account name set. Account name = $accountName") + infoPrint(credential.selectedAccountName) + val settings = getPreferences(Context.MODE_PRIVATE) + val editor = settings.edit() + editor.putString(PREF_ACCOUNT_NAME, accountName) + editor.apply() + refreshResults() } else if (resultCode == Activity.RESULT_CANCELED) { infoPrint("Account Unspecified") APIStatusMessage = "Account unspecified." @@ -314,28 +279,6 @@ class MainActivity : AppCompatActivity() { } } - fun refreshUI() { - try { - when (selectedFragment!!.javaClass){ - StatusFragment::class.java -> { - selectedFragment = StatusFragment.newInstance(APIOutList) - supportFragmentManager.beginTransaction().replace(R.id.fragment_container, - selectedFragment!!).commit() - println(" *** Refreshed Status UI") - } - ScheduleFragment::class.java -> { - selectedFragment = ScheduleFragment.newInstance(APIOutList) - supportFragmentManager.beginTransaction().replace(R.id.fragment_container, - selectedFragment!!).commit() - println(" *** Refreshed Schedule UI") - } - else -> println(" *** UI is not status.") - } - } catch (e: Exception) { - System.err.println("Caught Exception\n$e") - } - - } /** * Clear any existing Google Calendar API data from the TextView and update @@ -384,7 +327,6 @@ class MainActivity : AppCompatActivity() { APIOutList.add(event) } } - isFree } } } @@ -424,14 +366,11 @@ class MainActivity : AppCompatActivity() { } } - private fun infoPrint(info: Any?) { - if (info != null) - println("MAIN_: " + info!!) - else println("MAIN_: null!?!?!?") + private fun infoPrint(info: Any) { + println("MAIN_: $info") } companion object { - internal val REQUEST_ACCOUNT_PICKER = 1000 internal val REQUEST_AUTHORIZATION = 1001 internal val REQUEST_GOOGLE_PLAY_SERVICES = 1002 @@ -440,8 +379,19 @@ class MainActivity : AppCompatActivity() { lateinit var centralClock: TextClock - //UI Elements visible throughout the app - var selectedFragment: Fragment? = null } + private inner class SlidingPagerAdapter(fm: FragmentManager): FragmentStatePagerAdapter(fm){ + override fun getCount(): Int = fragments.size + override fun getItem(p0: Int): Fragment = fragments[p0] + } +} + +@Parcelize +data class Event(val summary: String, val startDate: Date, + val endDate: Date, val location: String): Parcelable{ + fun isHappeningNow(): Boolean{ + val now = Date() + return now.before(startDate) + } } \ No newline at end of file diff --git a/app/src/main/java/edu/rit/csh/bettervent/MainActivityViewModel.kt b/app/src/main/java/edu/rit/csh/bettervent/MainActivityViewModel.kt new file mode 100644 index 0000000..5eebd5c --- /dev/null +++ b/app/src/main/java/edu/rit/csh/bettervent/MainActivityViewModel.kt @@ -0,0 +1,28 @@ +package edu.rit.csh.bettervent + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import java.util.* +import kotlin.collections.ArrayList + +class MainActivityViewModel: ViewModel(){ + private val events: MutableLiveData> by lazy { + MutableLiveData>().also{ + loadEvents() + } + } + + fun getEvents(): LiveData> { + return events + } + + private fun loadEvents(): ArrayList{ + //TODO: get the Events + return ArrayList() + } + + fun addEvent(e: Event){ + events.value?.add(e) + } +} diff --git a/app/src/main/java/edu/rit/csh/bettervent/ParticipantListAdapter.kt b/app/src/main/java/edu/rit/csh/bettervent/ParticipantListAdapter.kt index f1fa73f..7720d05 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/ParticipantListAdapter.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/ParticipantListAdapter.kt @@ -4,7 +4,7 @@ import android.app.AlertDialog import android.content.Context import android.content.DialogInterface import android.graphics.Typeface -import android.support.v7.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView import android.text.InputType import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/java/edu/rit/csh/bettervent/QuickModeFragment.kt b/app/src/main/java/edu/rit/csh/bettervent/QuickModeFragment.kt index f6d2204..cfb0944 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/QuickModeFragment.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/QuickModeFragment.kt @@ -4,10 +4,8 @@ import android.app.AlertDialog import android.content.DialogInterface import android.graphics.Typeface import android.os.Bundle -import android.support.constraint.ConstraintLayout -import android.support.v4.app.Fragment -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager import android.text.InputType import android.view.LayoutInflater import android.view.View @@ -15,6 +13,10 @@ import android.view.ViewGroup import android.widget.Button import android.widget.EditText import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.fragment_quick_mode.* +import kotlinx.android.synthetic.main.fragment_quick_mode.view.* import java.util.ArrayList @@ -24,13 +26,11 @@ class QuickModeFragment : Fragment() { private var quickModeLayout: ConstraintLayout? = null - private var recyclerView: RecyclerView? = null private var adapter: RecyclerView.Adapter<*>? = null private var layoutManager: RecyclerView.LayoutManager? = null private var participantsLabel: TextView? = null private var nameSetLabel: TextView? = null - private var eventName: TextView? = null private var addButton: Button? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -40,21 +40,19 @@ class QuickModeFragment : Fragment() { quickModeLayout = view.findViewById(R.id.quick_mode_layout) - recyclerView = view.findViewById(R.id.participants_list) // use a linear layout manager layoutManager = LinearLayoutManager(this.context) - recyclerView!!.layoutManager = layoutManager + participants_list.layoutManager = layoutManager // specify an adapter adapter = ParticipantListAdapter(this.context!!, participants) - recyclerView!!.adapter = adapter + view.participants_list.adapter = adapter participantsLabel = view.findViewById(R.id.label_participants) nameSetLabel = view.findViewById(R.id.name_set_label) - eventName = view.findViewById(R.id.event_name) - eventName!!.setOnClickListener { + view.event_name.setOnClickListener { val builder = AlertDialog.Builder(context) builder.setTitle("Enter event title") @@ -66,16 +64,16 @@ class QuickModeFragment : Fragment() { // Set up the button builder.setPositiveButton("OK") { dialog, which -> val title = input.text.toString() - eventName!!.text = title + view.event_name.text = title //Change appearance of UI to indicate the room is reserved addButton!!.isEnabled = true quickModeLayout!!.setBackgroundColor(resources.getColor(R.color.CSHRed)) nameSetLabel!!.setTextColor(resources.getColor(R.color.white)) - eventName!!.setTextColor(resources.getColor(R.color.white)) + view.event_name.setTextColor(resources.getColor(R.color.white)) participantsLabel!!.setTextColor(resources.getColor(R.color.white)) nameSetLabel!!.visibility = View.VISIBLE MainActivity.centralClock.setTextColor(-0x1) - eventName!!.setTypeface(null, Typeface.BOLD) + view.event_name.setTypeface(null, Typeface.BOLD) } builder.setNegativeButton("Cancel") { dialog, which -> dialog.cancel() } builder.show() @@ -101,7 +99,7 @@ class QuickModeFragment : Fragment() { adapter!!.notifyItemInserted(participants.size - 1) infoPrint("Added new person.") } - builder.setNegativeButton("Cancel") { dialog, which -> dialog.cancel() } + builder.setNegativeButton("Cancel") { dialog, _ -> dialog.cancel() } builder.show() } diff --git a/app/src/main/java/edu/rit/csh/bettervent/ScheduleFragment.kt b/app/src/main/java/edu/rit/csh/bettervent/ScheduleFragment.kt index a3c7a99..c4d1801 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/ScheduleFragment.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/ScheduleFragment.kt @@ -1,7 +1,7 @@ package edu.rit.csh.bettervent import android.os.Bundle -import android.support.v4.app.Fragment +import androidx.fragment.app.Fragment import android.util.TypedValue import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/java/edu/rit/csh/bettervent/SettingsFragment.kt b/app/src/main/java/edu/rit/csh/bettervent/SettingsFragment.kt index 1de7124..dccd923 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/SettingsFragment.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/SettingsFragment.kt @@ -3,7 +3,7 @@ package edu.rit.csh.bettervent import android.content.Context import android.content.SharedPreferences import android.os.Bundle -import android.support.v4.app.Fragment +import androidx.fragment.app.Fragment import android.util.Log import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/java/edu/rit/csh/bettervent/StatusFragment.kt b/app/src/main/java/edu/rit/csh/bettervent/StatusFragment.kt index 2114c86..2b341ca 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/StatusFragment.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/StatusFragment.kt @@ -1,78 +1,46 @@ package edu.rit.csh.bettervent -import android.app.AlertDialog import android.content.Context import android.content.SharedPreferences import android.os.Bundle -import android.support.v4.app.Fragment -import android.text.InputType -import android.text.method.PasswordTransformationMethod +import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.EditText -import android.widget.LinearLayout -import android.widget.RelativeLayout -import com.google.api.client.util.DateTime -import com.google.api.services.calendar.model.Event import kotlinx.android.synthetic.main.fragment_status.* import kotlinx.android.synthetic.main.fragment_status.view.* -import kotlinx.android.synthetic.main.password_alert.* import kotlinx.android.synthetic.main.password_alert.view.* import org.jetbrains.anko.alert import org.jetbrains.anko.noButton import org.jetbrains.anko.yesButton -import java.io.Serializable +import java.text.SimpleDateFormat +import java.util.* +import kotlin.collections.ArrayList +import kotlin.system.exitProcess -class StatusFragment : Fragment() { +class StatusFragment : Fragment(){ private lateinit var appSettings: SharedPreferences // Settings object containing user preferences. + private lateinit var events: ArrayList + private lateinit var listener: OpenSettingsListener - var events: ArrayList = ArrayList() - - // Variables for storing what the status should read out as - var currentTitle: String? = null - lateinit var currentTime: String - var nextTitle: String? = null - lateinit var nextTime: String - - /** - * Extract information from the bundle that may have been provided with the StatusFragment, - * inflate status_layout and set it as the currently active view, then make references to all of - * the various pieces of the UI so that the class can update the UI with the API data. - * - * @param inflater - * @param container - * @param savedInstanceState - * @return - */ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { infoPrint("Loaded Status Fragment.") - // Load up app settings to fetch passwords and background colors. appSettings = context!!.getSharedPreferences( getString(R.string.preference_file_key), Context.MODE_PRIVATE) - val args = arguments - if (args != null) { - events.addAll(args.getSerializable("events") as List) - getCurrentAndNextEvents() - - } else { - infoPrint("ERROR! NO DATA FOUND!") - } - val view = inflater.inflate(R.layout.fragment_status, container, false) MainActivity.centralClock.setTextColor(-0x1) - fun showAlertWithFunction(onSuccess: () -> Unit){ - context!!.alert("Enter Password:"){ + fun showAlertWithFunction(onSuccess: () -> Unit) { + context!!.alert("Enter Password:") { val v = layoutInflater.inflate(R.layout.password_alert, null) customView = v - fun checkPassword(pw: String){ + fun checkPassword(pw: String) { if (pw == appSettings!!.getString("edu.rit.csh.bettervent.password", "")) onSuccess() } yesButton { checkPassword(v.password_et.text.toString()) } @@ -81,23 +49,12 @@ class StatusFragment : Fragment() { } view.leave_button.setOnClickListener { - showAlertWithFunction { System.exit(0) } + showAlertWithFunction { exitProcess(0) } } view.settings_button.setOnClickListener { - MainActivity.selectedFragment = SettingsFragment() - - showAlertWithFunction { fragmentManager!!.beginTransaction().replace(R.id.fragment_container, - MainActivity.selectedFragment as SettingsFragment).commit() } - } - - if (currentTitle == null) { - nextTime = "" - nextTitle = nextTime - currentTime = nextTitle as String - currentTitle = currentTime + showAlertWithFunction { } } - if (nextTitle == null) nextTitle = "" return view } @@ -106,64 +63,17 @@ class StatusFragment : Fragment() { * @param savedInstanceState */ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - infoPrint("Fragment Event Title: " + currentTitle!!) - setRoomStatus() + infoPrint("Fragment Event Title: ${events[0].summary}") + updateCurrentAndNextEventsInUI() } - /** - * - */ - private fun setRoomStatus() { - // Set current status of the room - if (currentTitle != "") { - free_label.visibility = View.INVISIBLE - reserved_label.visibility = View.VISIBLE - event_title.text = currentTitle - event_time!!.text = currentTime - status_layout.setBackgroundColor(resources.getColor(R.color.CSHRed)) - } else { - next_event_title.textSize = 64F - next_event_time.textSize = 32F - - reserved_label.visibility = View.INVISIBLE - free_label.visibility = View.VISIBLE - event_title.text = "" - event_time.text = "" - event_title.visibility = View.GONE - event_time.visibility = View.GONE - status_layout.setBackgroundColor(resources.getColor(R.color.CSHGreen)) - } - - if (currentTitle == "") { -// val next_label_params = next_label.layoutParams as RelativeLayout.LayoutParams -// next_label_params.setMargins(0, 128, 0, 0) //substitute parameters for left, top, right, bottom -// next_event_title.layoutParams = next_label_params - - val next_event_title_params = next_event_title.layoutParams as RelativeLayout.LayoutParams - next_event_title_params.setMargins(0, 72, 0, 0) //substitute parameters for left, top, right, bottom - next_event_title.layoutParams = next_event_title_params - - val separator_params = separator.layoutParams as RelativeLayout.LayoutParams - separator_params.setMargins(0, 0, 0, 0) //substitute parameters for left, top, right, bottom - separator.layoutParams = separator_params - - - } - - // Set the future status of the room - if (nextTitle != "") { - next_label.visibility = View.VISIBLE - next_event_title.text = nextTitle - next_event_time.text = nextTime - } else { - val next_event_title_params = next_event_title.layoutParams as RelativeLayout.LayoutParams - next_event_title_params.setMargins(0, 192, 0, 0) //substitute parameters for left, top, right, bottom - next_event_title.layoutParams = next_event_title_params - - next_label.visibility = View.GONE - next_event_time.visibility = View.GONE - next_event_title.text = "There are no upcoming events." - next_event_time.text = "" + override fun onAttach(context: Context) { + context.let { super.onAttach(it) + if (it is OpenSettingsListener) { + listener = it + } else { + throw ClassCastException("$it must implement OpenSettingsListener.") + } } } @@ -173,68 +83,51 @@ class StatusFragment : Fragment() { * values for currentEventTitle, currentEventTime, nextEventTitle, and * nextEventTime. */ - private fun getCurrentAndNextEvents() { - if (events == null) - infoPrint("There may have been an issue getting the data." + "\nor maybe there was no data.") - if (events == null || events!!.isEmpty()) { - nextTime = "" - nextTitle = nextTime - currentTime = nextTitle as String - currentTitle = currentTime - } else { - //Here's all the data we'll need. - val summary = events!![0].summary - var start: DateTime? = events!![0].start.dateTime - val end = events!![0].end.dateTime + private fun updateCurrentAndNextEventsInUI() { - if (start == null) { - // If the event will last all day then only use the event title. - start = events!![0].start.date - currentTitle = summary - currentTime = "All day" - } else { - // If the event has a set start and end time then check if it's now or later. - val now = DateTime(System.currentTimeMillis()) - if (start.value > now.value) { - // If the first event will happen in the future - // Then there is no current event. - currentTitle = "" - currentTime = "" - nextTitle = summary - nextTime = formatDateTime(start) + " — " + formatDateTime(end) - } else { - // Set current event to first event if it's happening right now. - currentTitle = summary - currentTime = formatDateTime(start) + " — " + formatDateTime(end) - if (events!!.size > 1) - // Get the next event after this one - getNextEvent() + events.also { + when { + it.isEmpty() -> { + setRoomAsEmpty(); setNoNextEvent() + } + it[0].isHappeningNow() and (it.size == 1) -> setCurrentEvent(it[0]) + it.size == 1 -> { + setRoomAsEmpty(); setNextEvent(it[0]) + } + else -> { + setCurrentEvent(it[0]); setNextEvent(it[1]) } } } } - /** - * Takes the second index of APIOutList (the List of Events generated by the API) - * and sets nextEventTitle and nextEventTime. - */ - private fun getNextEvent() { - try { - val nextEventSummary = events!![1].summary - var nextEventStart: DateTime? = events!![1].start.dateTime - val nextEventEnd = events!![1].end.dateTime - if (nextEventStart == null) { - // All-day events don't have start times, so just use - // the start date. - nextEventStart = events!![1].start.date - } - nextTitle = nextEventSummary - nextTime = formatDateTime(nextEventStart!!) + " — " + formatDateTime(nextEventEnd) - } catch (e: Exception) { - nextTitle = "" - nextTime = "" - } + private fun setRoomAsEmpty(){ + free_label.visibility = View.VISIBLE + reserved_label.visibility = View.INVISIBLE + event_title.text = "" + event_time.text = "" + status_layout.setBackgroundColor(resources.getColor(R.color.CSHGreen)) + } + + private fun setNoNextEvent(){ + next_label.visibility = View.INVISIBLE + next_event_time.text = "" + next_event_title.text = "There are no upcoming events." + } + + private fun setCurrentEvent(e: Event){ + free_label.visibility = View.INVISIBLE + reserved_label.visibility = View.VISIBLE + event_title.text = e.summary + event_time.text = "${formatDate(e.startDate)} - ${formatDate(e.endDate)}" + status_layout.setBackgroundColor(resources.getColor(R.color.CSHRed)) + } + + private fun setNextEvent(e: Event){ + next_label.visibility = View.VISIBLE + next_event_time.text = "${formatDate(e.startDate)} - ${formatDate(e.endDate)}" + next_event_title.text = e.summary } /** @@ -243,31 +136,19 @@ class StatusFragment : Fragment() { * @param dateTime: DateTime to make readable * @return: HH:MM on YYYY/MM/DD */ - private fun formatDateTime(dateTime: DateTime): String { - return if (dateTime.isDateOnly) { - dateTime.toString() - } else { - val t = dateTime.toString().split("T".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - val time = t[1].substring(0, 5) - val date = t[0].split("-".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - val dateString = date[0] + "/" + date[1] + "/" + date[2] - - "$time on $dateString" - } + private fun formatDate(inputDate: Date): String { + val simpleTimeFormat = SimpleDateFormat("HH:MM") + val simpleDateFormat = SimpleDateFormat("YYYY/MM/DD") + val time = simpleTimeFormat.format(inputDate) + val date = simpleDateFormat.format(inputDate) + return "$time on $date" } private fun infoPrint(info: String) { println("STAT_: $info") } - - companion object { - - fun newInstance(events: List): StatusFragment { - val f = StatusFragment() - val args = Bundle() - args.putSerializable("events", events as Serializable) - f.arguments = args - return f - } - } } + +interface OpenSettingsListener{ + fun openSettings() +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 5171c38..7189ad1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,5 +1,6 @@ - - + android:visibility="visible" + android:id="@+id/pager" /> - + app:srcCompat="@drawable/ic_home_black_24dp" /> - - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main_loading.xml b/app/src/main/res/layout/activity_main_loading.xml new file mode 100644 index 0000000..32ffc56 --- /dev/null +++ b/app/src/main/res/layout/activity_main_loading.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_quick_mode.xml b/app/src/main/res/layout/fragment_quick_mode.xml index 5287a42..afa0e04 100644 --- a/app/src/main/res/layout/fragment_quick_mode.xml +++ b/app/src/main/res/layout/fragment_quick_mode.xml @@ -1,12 +1,12 @@ - - - - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_schedule.xml b/app/src/main/res/layout/fragment_schedule.xml index c204d89..25c89e6 100644 --- a/app/src/main/res/layout/fragment_schedule.xml +++ b/app/src/main/res/layout/fragment_schedule.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 82618ce..d546dea 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,6 +6,8 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. +android.enableJetifier=true +android.useAndroidX=true org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit From 935aecdd37727ae82146304b8a96319eecfcac45 Mon Sep 17 00:00:00 2001 From: EricKarschner37 Date: Sat, 12 Oct 2019 12:36:53 -0400 Subject: [PATCH 02/10] Refactor code to include EventActivity to hold key Fragments after sign in --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 6 +- .../edu/rit/csh/bettervent/ApiAsyncTask.kt | 80 ------ .../edu/rit/csh/bettervent/EventActivity.kt | 173 +++++++++++++ .../edu/rit/csh/bettervent/MainActivity.kt | 238 +++++------------- .../csh/bettervent/MainActivityViewModel.kt | 28 --- .../rit/csh/bettervent/QuickModeFragment.kt | 23 +- .../rit/csh/bettervent/ScheduleFragment.kt | 68 ++--- .../rit/csh/bettervent/SettingsFragment.kt | 2 +- .../edu/rit/csh/bettervent/StatusFragment.kt | 56 +++-- .../{activity_main.xml => activity_event.xml} | 1 - .../main/res/layout/fragment_quick_mode.xml | 138 +++++----- app/src/main/res/layout/fragment_schedule.xml | 13 +- app/src/main/res/values/strings.xml | 3 + .../rit/csh/bettervent/ExampleUnitTest.java | 20 +- 15 files changed, 399 insertions(+), 451 deletions(-) delete mode 100644 app/src/main/java/edu/rit/csh/bettervent/ApiAsyncTask.kt create mode 100644 app/src/main/java/edu/rit/csh/bettervent/EventActivity.kt delete mode 100644 app/src/main/java/edu/rit/csh/bettervent/MainActivityViewModel.kt rename app/src/main/res/layout/{activity_main.xml => activity_event.xml} (98%) diff --git a/app/build.gradle b/app/build.gradle index a0559b9..6d2f5e1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,6 +33,7 @@ dependencies { implementation 'androidx.vectordrawable:vectordrawable:1.1.0' implementation 'org.jetbrains.anko:anko-commons:0.10.8' implementation 'org.jetbrains.anko:anko-design:0.10.8' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2f4bac8..0cd6765 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,7 +21,11 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Design.Light.NoActionBar"> - + + + () { - - private val appSettings: SharedPreferences? = null - - /** - * Background task to call Google Calendar API. - * @param params no parameters needed for this task. - */ - override fun doInBackground(vararg params: Void): Void? { - try { - mainActivity.clearResultsText() - mainActivity.updateResultsText(getDataFromApi(mainActivity.calendarID!!, mainActivity.maxResults)) - - } catch (availabilityException: GooglePlayServicesAvailabilityIOException) { - // mainActivity.showGooglePlayServicesAvailabilityErrorDialog( - // availabilityException.getConnectionStatusCode()); //TODO: Display error when unable to fetch events. - System.err.println("Error connecting to Google Play Services. Error code: " + availabilityException.connectionStatusCode) - - - } catch (userRecoverableException: UserRecoverableAuthIOException) { - mainActivity.startActivityForResult( - userRecoverableException.intent, - MainActivity.REQUEST_AUTHORIZATION) - - } catch (e: IOException) { - mainActivity.updateStatus("The following error occurred: " + e.message) - } - - return null - } - - /** - * Fetch a list of the next 10 events from the primary calendar. - * @return List of Strings describing returned events. - * @throws IOException - */ - @Throws(IOException::class) - private fun getDataFromApi(calendarID: String, maxResults: Int): List { - // Load up app settings to fetch passwords and background colors. - // System.out.println("*** Attempting to get data from API. ***"); - // List the next 10 events from the primary calendar. - val now = DateTime(System.currentTimeMillis()) - val events = mainActivity.mService.events().list(calendarID) - .setMaxResults(maxResults) - .setTimeMin(now) - .setOrderBy("startTime") - .setSingleEvents(true) - .execute() -// println("*** items: " + events) - return ArrayList() - } - -} \ No newline at end of file diff --git a/app/src/main/java/edu/rit/csh/bettervent/EventActivity.kt b/app/src/main/java/edu/rit/csh/bettervent/EventActivity.kt new file mode 100644 index 0000000..cd63c2e --- /dev/null +++ b/app/src/main/java/edu/rit/csh/bettervent/EventActivity.kt @@ -0,0 +1,173 @@ +package edu.rit.csh.bettervent + +import android.content.Context +import android.content.SharedPreferences +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.util.Log +import android.widget.TextClock +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter +import com.google.api.client.extensions.android.http.AndroidHttp +import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential +import com.google.api.client.json.JsonFactory +import com.google.api.client.json.gson.GsonFactory +import com.google.api.client.util.DateTime +import com.google.api.client.util.ExponentialBackOff +import com.google.api.services.calendar.Calendar +import com.google.api.services.calendar.CalendarScopes +import com.google.api.services.calendar.model.Events +import kotlinx.android.synthetic.main.activity_event.* +import org.jetbrains.anko.custom.async +import org.jetbrains.anko.doAsync +import org.jetbrains.anko.uiThread +import java.util.* +import kotlin.collections.ArrayList + +class EventActivity : AppCompatActivity(), OpenSettingsListener{ + private lateinit var statusFragment: StatusFragment + private lateinit var scheduleFragment: ScheduleFragment + private lateinit var quickModeFragment: QuickModeFragment + private lateinit var fragments: List + private lateinit var mService: Calendar + private lateinit var settings: SharedPreferences + private val events = ArrayList() + + private val transport = AndroidHttp.newCompatibleTransport() + private val jsonFactory: JsonFactory = GsonFactory.getDefaultInstance() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContentView(R.layout.activity_event) + Log.i("EventActivity", "Started activity") + refresh_button.setOnClickListener { + updateEvents() + } + + settings = getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE) + mService = getCalendarService() + + val bundle = Bundle() + bundle.putParcelableArrayList("events", events) + statusFragment = StatusFragment() + statusFragment.arguments = bundle + scheduleFragment = ScheduleFragment() + scheduleFragment.arguments = bundle + quickModeFragment = QuickModeFragment() + fragments = listOf(statusFragment, scheduleFragment, quickModeFragment) + + pager.adapter = SlidingPagerAdapter(supportFragmentManager) + centralClock = findViewById(R.id.central_clock) + + updateEvents() + } + + private fun getCalendarService(): Calendar{ + val credential = GoogleAccountCredential.usingOAuth2( + applicationContext, listOf(*SCOPES)) + .setBackOff(ExponentialBackOff()) + .setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, "")) + + Log.i("EventActivity", "${credential.selectedAccountName}") + + return Calendar.Builder( + transport, jsonFactory, credential) + .setApplicationName("Google Calendar API Android Quickstart") + .build() + } + + private fun updateEvents(){ + doAsync{ + val events = getEventsFromServer() + uiThread { + handleEvents(parseEvents(events)) + } + } + } + + private fun getEventsFromServer(): Events { + val calendarId = settings.getString("edu.rit.csh.bettervent.calendarid", "rti648k5hv7j3ae3a3rum8potk@group.calendar.google.com") + + val maxResultsStr = settings.getString("edu.rit.csh.bettervent.maxresults", "") + val maxResults = if (maxResultsStr !== "" && maxResultsStr != null) + Integer.parseInt(maxResultsStr) + else { + Log.i("EventActivity", "Max Results not set. Defaulting to 100.") + 100 + } + + val now = DateTime(System.currentTimeMillis()) + return mService.events().list(calendarId) + .setMaxResults(maxResults) + .setTimeMin(now) + .setOrderBy("startTime") + .setSingleEvents(true) + .execute() + } + + private fun parseEvents(calendarEvents: Events): ArrayList{ + val events = ArrayList() + for (calendarEvent in calendarEvents.items){ + val event = calendarEvent.parseToEvent() + event?.also{ + Log.i("EventActivity", "Event added: $event") + events.add(it) + } + } + return events + } + + private fun handleEvents(inEvents: ArrayList){ + events.removeAll(events) + + if (inEvents.isNotEmpty()){ + val eventKeyword = settings.getString("edu.rit.csh.bettervent.filterkeywords", "")!! + events.removeAll(events) + for (event in inEvents) { + val eventFieldToCheck = if (settings.getBoolean("edu.rit.csh.bettervent.filterbytitle", false)) { + event.summary + } else { + event.location + } + if (eventKeyword.isNotEmpty()) { + if (eventFieldToCheck.toLowerCase(Locale.getDefault()).contains(eventKeyword.toLowerCase(Locale.getDefault()))) { + events.add(event) + } + } else { + events.add(event) + } + } + } + } + + private fun com.google.api.services.calendar.model.Event.parseToEvent(): Event?{ + location?.also{ + return Event(summary, + Date(start.dateTime.value), + Date(end.dateTime.value), + location) + } + return null + } + + private inner class SlidingPagerAdapter(fm: FragmentManager): FragmentStatePagerAdapter(fm){ + override fun getCount(): Int = fragments.size + override fun getItem(p0: Int): Fragment { + Log.i("MainActivity", "Swipe index: $p0") + bottom_navigation.selectedItemId = p0 + return fragments[p0] + } + } + + override fun openSettings() { + Log.i("EventActivity", "Open settings") + } + + companion object { + lateinit var centralClock: TextClock + private const val PREF_ACCOUNT_NAME = "accountName" + private val SCOPES = arrayOf(CalendarScopes.CALENDAR_READONLY) + } +} diff --git a/app/src/main/java/edu/rit/csh/bettervent/MainActivity.kt b/app/src/main/java/edu/rit/csh/bettervent/MainActivity.kt index 3e5e11d..463a85e 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/MainActivity.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/MainActivity.kt @@ -3,8 +3,6 @@ package edu.rit.csh.bettervent import android.accounts.Account import android.app.admin.DevicePolicyManager import android.content.ComponentName -import com.google.android.material.floatingactionbutton.FloatingActionButton -import androidx.fragment.app.Fragment import androidx.appcompat.app.AppCompatActivity import android.os.Bundle @@ -12,69 +10,29 @@ import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccoun import android.accounts.AccountManager import android.app.Activity -import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProviders import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.net.ConnectivityManager -import android.os.Handler import android.os.Parcelable import android.util.Log -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentStatePagerAdapter -import android.widget.TextClock import android.widget.Toast -import com.google.android.gms.auth.api.signin.GoogleSignIn -import com.google.android.gms.auth.api.signin.GoogleSignInAccount -import com.google.android.gms.auth.api.signin.GoogleSignInOptions import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.GooglePlayServicesUtil -import com.google.android.gms.common.api.ApiException -import com.google.android.gms.tasks.Task -import com.google.api.client.extensions.android.http.AndroidHttp -import com.google.api.client.json.JsonFactory -import com.google.api.client.json.gson.GsonFactory -import com.google.api.client.util.DateTime -import com.google.api.client.util.ExponentialBackOff import com.google.api.services.calendar.CalendarScopes import kotlinx.android.parcel.Parcelize -import kotlinx.android.synthetic.main.activity_main.* -import java.text.SimpleDateFormat import java.util.* -class MainActivity : AppCompatActivity(), OpenSettingsListener { - override fun openSettings() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - - internal lateinit var mService: com.google.api.services.calendar.Calendar - - internal lateinit var credential: GoogleAccountCredential +class MainActivity : AppCompatActivity(){ // This MainActivity gets the data from the API, and holds it // as a list. The Fragments then update themselves using that. - private lateinit var model: MainActivityViewModel - private lateinit var statusFragment: StatusFragment - private lateinit var scheduleFragment: ScheduleFragment - private lateinit var quickModeFragment: QuickModeFragment - - private val APIOutList = ArrayList() - internal val transport = AndroidHttp.newCompatibleTransport() - internal val jsonFactory: JsonFactory = GsonFactory.getDefaultInstance() var calendarID: String? = null var maxResults: Int = 0 - private var mAppSettings: SharedPreferences? = null + private lateinit var mAppSettings: SharedPreferences - private lateinit var APIStatusMessage: String - var isReserved = true - private lateinit var refreshButton: FloatingActionButton - - private lateinit var fragments: List - private lateinit var account: GoogleSignInAccount - private lateinit var mGoogleSignInClient: GoogleSignInAccount - private lateinit var gso: GoogleSignInOptions + private lateinit var apiStatusMessage: String /** * Checks whether the device currently has a network connection. @@ -106,9 +64,6 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { return true } - - - /** * Checks the times of the first event in APIOutList (the List of Events generated by the API) * and if the current time is within those times, then the room is booked @@ -122,31 +77,24 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main_loading) - gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestEmail() - .build() - - model = ViewModelProviders.of(this)[MainActivityViewModel::class.java] - model.getEvents().observe(this, Observer> { events -> - setupMainView(events) - }) - // Load up app settings to fetch passwords and background colors. mAppSettings = getSharedPreferences( - getString(R.string.preference_file_key), Context.MODE_PRIVATE) + getString(R.string.preference_file_key), Context.MODE_PRIVATE)!! // Must restart for these preferences to take hold. - calendarID = mAppSettings!!.getString("edu.rit.csh.bettervent.calendarid", "") + //TODO: Prompt for calendarid if not found + calendarID = mAppSettings.getString("edu.rit.csh.bettervent.calendarid", "rti648k5hv7j3ae3a3rum8potk@group.calendar.google.com") val maxResultsStr = mAppSettings!!.getString("edu.rit.csh.bettervent.maxresults", "") - if (maxResultsStr !== "" && maxResultsStr != null) - maxResults = Integer.parseInt(maxResultsStr) + maxResults = if (maxResultsStr !== "" && maxResultsStr != null) + Integer.parseInt(maxResultsStr) else { infoPrint("Max Results not set. Defaulting to 100.") - maxResults = 100 + 100 } + //Following code allow the app packages to lock task in true kiosk mode // get policy manager val myDevicePolicyManager = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager @@ -162,34 +110,9 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { Toast.makeText(applicationContext, "Not owner", Toast.LENGTH_LONG).show() } - startLockTask() - - // Initialize credentials and service object. - val settings = getPreferences(Context.MODE_PRIVATE) - - - refreshResults() - - - } - - private fun setupMainView(events: ArrayList){ - refreshButton = findViewById(R.id.refresh_button) - refreshButton.setOnClickListener { - // TODO: figure out why you have to do this twice to make anything happen. - refreshResults() - } - - pager.adapter = SlidingPagerAdapter(supportFragmentManager) - centralClock = findViewById(R.id.central_clock) - - val bundle = Bundle() - bundle.putParcelableArrayList("events", events) - statusFragment = StatusFragment() - statusFragment.arguments = bundle - scheduleFragment = ScheduleFragment() - quickModeFragment = QuickModeFragment() - fragments = listOf(statusFragment, scheduleFragment, quickModeFragment) +// startLockTask() + Log.i("MainActivity", "End onCreate") + checkForAccount() } /** @@ -198,10 +121,8 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { */ override fun onResume() { super.onResume() - if (isGooglePlayServicesAvailable) { - refreshResults() - } else { - APIStatusMessage = "Google Play Services required: " + "after installing, close and relaunch this app." + if (!isGooglePlayServicesAvailable) { + apiStatusMessage = "Google Play Services required: " + "after installing, close and relaunch this app." } } @@ -215,14 +136,11 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { * @param data Intent (containing result data) returned by incoming * activity result. */ - override fun onActivityResult( - requestCode: Int, resultCode: Int, data: Intent?) { + override fun onActivityResult( requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) infoPrint("API Request code returned: $requestCode") when (requestCode) { - REQUEST_GOOGLE_PLAY_SERVICES -> if (resultCode == Activity.RESULT_OK) { - refreshResults() - } else { + REQUEST_GOOGLE_PLAY_SERVICES -> if (resultCode != Activity.RESULT_OK) { isGooglePlayServicesAvailable } REQUEST_ACCOUNT_PICKER -> { @@ -233,23 +151,19 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { val accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME) infoPrint("Account name = " + accountName!!) // credential.setSelectedAccountName(accountName); - credential.selectedAccount = Account(accountName, "edu.rit.csh.bettervent") + val selectedAccount = Account(accountName, "edu.rit.csh.bettervent") infoPrint("Account name set. Account name = $accountName") - infoPrint(credential.selectedAccountName) - val settings = getPreferences(Context.MODE_PRIVATE) - val editor = settings.edit() + infoPrint(selectedAccount.name) + val editor = mAppSettings.edit() editor.putString(PREF_ACCOUNT_NAME, accountName) editor.apply() - refreshResults() + checkForAccount() } else if (resultCode == Activity.RESULT_CANCELED) { infoPrint("Account Unspecified") - APIStatusMessage = "Account unspecified." + apiStatusMessage = "Account unspecified." } } REQUEST_AUTHORIZATION -> if (resultCode == Activity.RESULT_OK) { - if (credential.selectedAccountName.length < 1) - refreshResults() - } else { chooseAccount() } } @@ -257,28 +171,6 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { super.onActivityResult(requestCode, resultCode, data) } - /** - * Attempt to get a set of data from the Google Calendar API to display. If the - * email address isn't known yet, then call chooseAccount() method so the - * user can pick an account. - */ - private fun refreshResults() { - println("*** Refreshing results... ***") - if (credential.selectedAccountName == null) { - infoPrint("No account selected.") - chooseAccount() - } else { - if (isDeviceOnline) { - println("*** Executing APIAsyncTask. ***") - ApiAsyncTask(this).execute() - // TODO: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState ??? - } else { - println("*** Can't refresh calendar. ***") - APIStatusMessage = "No network connection available." - } - } - } - /** * Clear any existing Google Calendar API data from the TextView and update @@ -287,8 +179,8 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { */ fun clearResultsText() { runOnUiThread { - APIStatusMessage = "Retrieving data…" - APIStatusMessage = "" + apiStatusMessage = "Retrieving data…" + apiStatusMessage = "" } } @@ -298,38 +190,6 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { * UI thread). * @param dataEvents a List of Strings to populate the main TextView with. */ - fun updateResultsText(dataEvents: List?) { - runOnUiThread { - if (dataEvents == null) { - APIStatusMessage = "Error retrieving data!" - } else if (dataEvents.size == 0) { - APIStatusMessage = "No data found." - println("*** No data found. ***") - APIOutList.removeAll(APIOutList) - } else { - APIStatusMessage = "API Call Complete." - infoPrint("*** Events found. *** $dataEvents") - val eventKeyword = mAppSettings!!.getString("edu.rit.csh.bettervent.filterkeywords", "") - APIOutList.removeAll(APIOutList) - var eventFieldToCheck: String? - for (event in dataEvents) { - if (mAppSettings!!.getBoolean("edu.rit.csh.bettervent.filterbytitle", false)) { - eventFieldToCheck = event.summary - } else { - eventFieldToCheck = event.location - } - infoPrint(eventFieldToCheck) - if (eventKeyword!!.length > 0 && eventFieldToCheck != null) { - if (eventFieldToCheck.toLowerCase().contains(eventKeyword.toLowerCase())) { - APIOutList.add(event) - } - } else if (eventKeyword.length < 1) { - APIOutList.add(event) - } - } - } - } - } /** * Show a status message in the list header TextView; called from background @@ -337,7 +197,20 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { * @param message a String to display in the UI header TextView. */ fun updateStatus(message: String) { - runOnUiThread { APIStatusMessage = message } + runOnUiThread { apiStatusMessage = message } + } + + private fun checkForAccount(){ + val accountName = mAppSettings.getString(PREF_ACCOUNT_NAME, "")!! + Log.i("MainActivity", "Account Name: $accountName") + if (accountName.isEmpty()){ + chooseAccount() + Log.i("MainActivity", "Begin chooseAccount") + } else { + Log.i("MainActivity", "Start EventActivity") + val intent = Intent(this, EventActivity::class.java) + startActivity(intent) + } } /** @@ -345,6 +218,7 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { * account. */ private fun chooseAccount() { + val credential = GoogleAccountCredential.usingOAuth2(applicationContext, SCOPES) startActivityForResult( credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER) } @@ -355,7 +229,7 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { * @param connectionStatusCode code describing the presence (or lack of) * Google Play Services on this device. */ - internal fun showGooglePlayServicesAvailabilityErrorDialog( + private fun showGooglePlayServicesAvailabilityErrorDialog( connectionStatusCode: Int) { runOnUiThread { val dialog = GooglePlayServicesUtil.getErrorDialog( @@ -371,27 +245,29 @@ class MainActivity : AppCompatActivity(), OpenSettingsListener { } companion object { - internal val REQUEST_ACCOUNT_PICKER = 1000 - internal val REQUEST_AUTHORIZATION = 1001 - internal val REQUEST_GOOGLE_PLAY_SERVICES = 1002 - private val PREF_ACCOUNT_NAME = "accountName" - private val SCOPES = arrayOf(CalendarScopes.CALENDAR_READONLY) - - lateinit var centralClock: TextClock - - } + internal const val REQUEST_ACCOUNT_PICKER = 1000 + internal const val REQUEST_AUTHORIZATION = 1001 + internal const val REQUEST_GOOGLE_PLAY_SERVICES = 1002 + private const val PREF_ACCOUNT_NAME = "accountName" + val SCOPES = arrayListOf(CalendarScopes.CALENDAR_READONLY) - private inner class SlidingPagerAdapter(fm: FragmentManager): FragmentStatePagerAdapter(fm){ - override fun getCount(): Int = fragments.size - override fun getItem(p0: Int): Fragment = fragments[p0] } } @Parcelize -data class Event(val summary: String, val startDate: Date, - val endDate: Date, val location: String): Parcelable{ +data class Event(val summary: String, val start: Date, + val end: Date, val location: String): Parcelable{ fun isHappeningNow(): Boolean{ + return hasStarted() and !isOver() + } + + fun isOver(): Boolean{ + val now = Date() + return now.after(end) + } + + fun hasStarted(): Boolean{ val now = Date() - return now.before(startDate) + return start.before(now) } } \ No newline at end of file diff --git a/app/src/main/java/edu/rit/csh/bettervent/MainActivityViewModel.kt b/app/src/main/java/edu/rit/csh/bettervent/MainActivityViewModel.kt deleted file mode 100644 index 5eebd5c..0000000 --- a/app/src/main/java/edu/rit/csh/bettervent/MainActivityViewModel.kt +++ /dev/null @@ -1,28 +0,0 @@ -package edu.rit.csh.bettervent - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import java.util.* -import kotlin.collections.ArrayList - -class MainActivityViewModel: ViewModel(){ - private val events: MutableLiveData> by lazy { - MutableLiveData>().also{ - loadEvents() - } - } - - fun getEvents(): LiveData> { - return events - } - - private fun loadEvents(): ArrayList{ - //TODO: get the Events - return ArrayList() - } - - fun addEvent(e: Event){ - events.value?.add(e) - } -} diff --git a/app/src/main/java/edu/rit/csh/bettervent/QuickModeFragment.kt b/app/src/main/java/edu/rit/csh/bettervent/QuickModeFragment.kt index cfb0944..de485ca 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/QuickModeFragment.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/QuickModeFragment.kt @@ -1,7 +1,6 @@ package edu.rit.csh.bettervent import android.app.AlertDialog -import android.content.DialogInterface import android.graphics.Typeface import android.os.Bundle import androidx.fragment.app.Fragment @@ -12,8 +11,8 @@ import android.view.View import android.view.ViewGroup import android.widget.Button import android.widget.EditText +import android.widget.LinearLayout import android.widget.TextView -import androidx.constraintlayout.widget.ConstraintLayout import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.fragment_quick_mode.* import kotlinx.android.synthetic.main.fragment_quick_mode.view.* @@ -24,7 +23,7 @@ class QuickModeFragment : Fragment() { private val participants = ArrayList() - private var quickModeLayout: ConstraintLayout? = null + private var quickModeLayout: LinearLayout? = null private var adapter: RecyclerView.Adapter<*>? = null private var layoutManager: RecyclerView.LayoutManager? = null @@ -36,13 +35,21 @@ class QuickModeFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { infoPrint("Loaded QuickMode Fragment.") val view = inflater.inflate(R.layout.fragment_quick_mode, container, false) - MainActivity.centralClock.setTextColor(-0x1000000) - quickModeLayout = view.findViewById(R.id.quick_mode_layout) + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + + EventActivity.centralClock.setTextColor(-0x1000000) + + quickModeLayout = view.findViewById(R.id.quick_mode_view) // use a linear layout manager - layoutManager = LinearLayoutManager(this.context) + layoutManager = LinearLayoutManager(context) participants_list.layoutManager = layoutManager // specify an adapter @@ -72,7 +79,7 @@ class QuickModeFragment : Fragment() { view.event_name.setTextColor(resources.getColor(R.color.white)) participantsLabel!!.setTextColor(resources.getColor(R.color.white)) nameSetLabel!!.visibility = View.VISIBLE - MainActivity.centralClock.setTextColor(-0x1) + EventActivity.centralClock.setTextColor(-0x1) view.event_name.setTypeface(null, Typeface.BOLD) } builder.setNegativeButton("Cancel") { dialog, which -> dialog.cancel() } @@ -103,8 +110,6 @@ class QuickModeFragment : Fragment() { builder.show() } - - return view } fun infoPrint(info: String) { diff --git a/app/src/main/java/edu/rit/csh/bettervent/ScheduleFragment.kt b/app/src/main/java/edu/rit/csh/bettervent/ScheduleFragment.kt index c4d1801..ad70111 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/ScheduleFragment.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/ScheduleFragment.kt @@ -1,6 +1,7 @@ package edu.rit.csh.bettervent import android.os.Bundle +import android.util.Log import androidx.fragment.app.Fragment import android.util.TypedValue import android.view.LayoutInflater @@ -12,7 +13,7 @@ import com.alamkanak.weekview.MonthLoader import com.alamkanak.weekview.WeekView import com.alamkanak.weekview.WeekViewDisplayable import com.alamkanak.weekview.WeekViewEvent -import com.google.api.services.calendar.model.Event +import kotlinx.android.synthetic.main.fragment_status.* import java.io.Serializable import java.text.SimpleDateFormat @@ -20,10 +21,10 @@ import java.util.ArrayList import java.util.Calendar import java.util.Locale -class ScheduleFragment : Fragment(), MonthLoader.MonthChangeListener { +class ScheduleFragment : Fragment(){ lateinit var weekView: WeekView - private var events: List? = null + private lateinit var events: ArrayList override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -32,17 +33,17 @@ class ScheduleFragment : Fragment(), MonthLoader.MonthChangeListener { val args = arguments if (args != null) { infoPrint("Found events data") - events = args.getSerializable("events") as List - if (events != null && events!!.isNotEmpty()) - infoPrint("First event title: " + events!![0].summary) + events = args.getParcelableArrayList("events")!! + if ( events.isNotEmpty()) + infoPrint("First event title: " + events[0].summary) } else { infoPrint("ERROR! NO DATA FOUND!") } - MainActivity.centralClock.setTextColor(-0x1000000) + EventActivity.centralClock.setTextColor(-0x1000000) weekView = view.findViewById(R.id.week_view) - weekView.setMonthChangeListener(this as MonthLoader.MonthChangeListener) + weekView.setMonthChangeListener(MonthChangeListener() as MonthLoader.MonthChangeListener) weekView.numberOfVisibleDays = 7 // Lets change some dimensions to best fit the view. @@ -88,23 +89,34 @@ class ScheduleFragment : Fragment(), MonthLoader.MonthChangeListener { println("SCHE_: $info") } - override fun onMonthChange(startDate: Calendar, endDate: Calendar): List> { + companion object { + + fun newInstance(events: List?): ScheduleFragment { + val f = ScheduleFragment() + val args = Bundle() + args.putSerializable("events", events as Serializable) + f.arguments = args + return f + } + } + + inner class MonthChangeListener: MonthLoader.MonthChangeListener{ - val weekViewEvents = ArrayList>() + override fun onMonthChange(startDate: Calendar, endDate: Calendar): List> { - val color1 = resources.getColor(R.color.colorPrimaryDark) + val weekViewEvents = ArrayList>() - if (events != null) { - infoPrint("event size : " + events!!.size) - for (i in events!!.indices) { - val event = events!![i] + val color1 = resources.getColor(R.color.colorPrimaryDark) + infoPrint("event size : " + events.size) + for (i in events.indices) { + val event = events[i] val wve = WeekViewEvent() // Set ID (not the Google Calendar ID). - wve.setId(i.toLong()) + wve.id = i.toLong() // Set Title - wve.setTitle(event.summary) + wve.title = event.summary val newYear = startDate.get(Calendar.YEAR) val newMonth = startDate.get(Calendar.MONTH) @@ -113,17 +125,18 @@ class ScheduleFragment : Fragment(), MonthLoader.MonthChangeListener { try { // Start Time val startCal = Calendar.getInstance() - startCal.timeInMillis = event.start.dateTime.value + startCal.timeInMillis = event.start.time startCal.set(Calendar.MONTH, newMonth) startCal.set(Calendar.YEAR, newYear) - wve.setStartTime(startCal) + Log.i("ScheduleFragment", "Startcal: $startCal") + wve.startTime = startCal // End Time val endCal = Calendar.getInstance() - endCal.timeInMillis = event.end.dateTime.value + endCal.timeInMillis = event.end.time endCal.set(Calendar.MONTH, newMonth) endCal.set(Calendar.YEAR, newYear) - wve.setEndTime(endCal) + wve.endTime = endCal } catch (error: NullPointerException) { error.printStackTrace() wve.setIsAllDay(true) @@ -135,18 +148,7 @@ class ScheduleFragment : Fragment(), MonthLoader.MonthChangeListener { weekViewEvents.add(wve as WeekViewDisplayable) } - } - return weekViewEvents - } - - companion object { - - fun newInstance(events: List?): ScheduleFragment { - val f = ScheduleFragment() - val args = Bundle() - args.putSerializable("events", events as Serializable) - f.arguments = args - return f + return weekViewEvents } } } diff --git a/app/src/main/java/edu/rit/csh/bettervent/SettingsFragment.kt b/app/src/main/java/edu/rit/csh/bettervent/SettingsFragment.kt index dccd923..d2d747f 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/SettingsFragment.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/SettingsFragment.kt @@ -45,7 +45,7 @@ class SettingsFragment : Fragment() { "Password: [REDACTED]" ) - MainActivity.centralClock.setTextColor(-0x1000000) + EventActivity.centralClock.setTextColor(-0x1000000) view.calendar_id_prompt.setText(appSettings.getString(calendarIDString, "")) view.max_results_prompt.setText(appSettings.getString(maxResultsString, "")) diff --git a/app/src/main/java/edu/rit/csh/bettervent/StatusFragment.kt b/app/src/main/java/edu/rit/csh/bettervent/StatusFragment.kt index 2b341ca..fe7f9df 100644 --- a/app/src/main/java/edu/rit/csh/bettervent/StatusFragment.kt +++ b/app/src/main/java/edu/rit/csh/bettervent/StatusFragment.kt @@ -9,7 +9,6 @@ import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.fragment_status.* -import kotlinx.android.synthetic.main.fragment_status.view.* import kotlinx.android.synthetic.main.password_alert.view.* import org.jetbrains.anko.alert import org.jetbrains.anko.noButton @@ -28,42 +27,42 @@ class StatusFragment : Fragment(){ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { infoPrint("Loaded Status Fragment.") + + return inflater.inflate(R.layout.fragment_status, container, false) + } + + /** + * @param view + * @param savedInstanceState + */ + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // Load up app settings to fetch passwords and background colors. appSettings = context!!.getSharedPreferences( getString(R.string.preference_file_key), Context.MODE_PRIVATE) - val view = inflater.inflate(R.layout.fragment_status, container, false) + events = arguments?.getParcelableArrayList("events")!! - MainActivity.centralClock.setTextColor(-0x1) + EventActivity.centralClock.setTextColor(-0x1) fun showAlertWithFunction(onSuccess: () -> Unit) { - context!!.alert("Enter Password:") { + context?.alert("Enter Password:") { val v = layoutInflater.inflate(R.layout.password_alert, null) customView = v fun checkPassword(pw: String) { - if (pw == appSettings!!.getString("edu.rit.csh.bettervent.password", "")) onSuccess() + if (pw == appSettings.getString("edu.rit.csh.bettervent.password", "")) onSuccess() } yesButton { checkPassword(v.password_et.text.toString()) } noButton { dialog -> dialog.cancel() } - }.show() + }?.show() } - view.leave_button.setOnClickListener { + leave_button.setOnClickListener { showAlertWithFunction { exitProcess(0) } } - view.settings_button.setOnClickListener { - showAlertWithFunction { } + settings_button.setOnClickListener { + showAlertWithFunction { listener.openSettings() } } - return view - } - - /** - * @param view - * @param savedInstanceState - */ - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - infoPrint("Fragment Event Title: ${events[0].summary}") updateCurrentAndNextEventsInUI() } @@ -91,12 +90,15 @@ class StatusFragment : Fragment(){ it.isEmpty() -> { setRoomAsEmpty(); setNoNextEvent() } - it[0].isHappeningNow() and (it.size == 1) -> setCurrentEvent(it[0]) - it.size == 1 -> { - setRoomAsEmpty(); setNextEvent(it[0]) - } + it.size == 1 -> if (it[0].isHappeningNow()) setCurrentEvent(it[0]) else setNextEvent(it[0]) else -> { - setCurrentEvent(it[0]); setNextEvent(it[1]) + if (it[0].isHappeningNow()){ + setCurrentEvent(it[0]) + setNextEvent(it[1]) + } else { + setRoomAsEmpty() + setNextEvent(it[0]) + } } } } @@ -120,13 +122,13 @@ class StatusFragment : Fragment(){ free_label.visibility = View.INVISIBLE reserved_label.visibility = View.VISIBLE event_title.text = e.summary - event_time.text = "${formatDate(e.startDate)} - ${formatDate(e.endDate)}" + event_time.text = "${formatDate(e.start)} - ${formatDate(e.end)}" status_layout.setBackgroundColor(resources.getColor(R.color.CSHRed)) } private fun setNextEvent(e: Event){ next_label.visibility = View.VISIBLE - next_event_time.text = "${formatDate(e.startDate)} - ${formatDate(e.endDate)}" + next_event_time.text = "${formatDate(e.start)} - ${formatDate(e.end)}" next_event_title.text = e.summary } @@ -137,8 +139,8 @@ class StatusFragment : Fragment(){ * @return: HH:MM on YYYY/MM/DD */ private fun formatDate(inputDate: Date): String { - val simpleTimeFormat = SimpleDateFormat("HH:MM") - val simpleDateFormat = SimpleDateFormat("YYYY/MM/DD") + val simpleTimeFormat = SimpleDateFormat("HH:mm", Locale.getDefault()) + val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) val time = simpleTimeFormat.format(inputDate) val date = simpleDateFormat.format(inputDate) return "$time on $date" diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_event.xml similarity index 98% rename from app/src/main/res/layout/activity_main.xml rename to app/src/main/res/layout/activity_event.xml index 7189ad1..a86e1f4 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_event.xml @@ -15,7 +15,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerHorizontal="true" - android:visibility="visible" android:id="@+id/pager" /> - + android:background="@color/white" + android:orientation="vertical" + android:id="@+id/quick_mode_view" + android:gravity="center_horizontal"> - + - + - + - + - +