Commit 4a14058e authored by Roger Barton's avatar Roger Barton
Browse files

Can easily add micro app now

Renamed Requests for better auto completion
parent 4805173f
......@@ -2,7 +2,6 @@ package ch.amiv.android_app.core;
import android.content.Context;
import android.content.Intent;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
......@@ -263,7 +262,7 @@ public class IntroActivity extends AppCompatActivity {
SetPage(Page.EDIT_PROFILE, true);
RefreshPageUI(Page.EDIT_PROFILE);
btnNext.setVisibility(View.INVISIBLE);
Requests.FetchUserData(getApplicationContext(), viewPager, new Requests.OnDataReceivedCallback() {
Request.FetchUserData(getApplicationContext(), viewPager, new Request.OnDataReceivedCallback() {
@Override
public void OnDataReceived() {
SetProfileUI();
......@@ -336,7 +335,7 @@ public class IntroActivity extends AppCompatActivity {
*/
private void UpdateProfile(){
if(UserInfo.current.SetRFID(rfidField.getText().toString()))
Requests.PatchUserData(getApplicationContext());
Request.PatchUserData(getApplicationContext());
}
//endregion
......
package ch.amiv.android_app.core;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
......@@ -34,10 +32,10 @@ import ch.amiv.android_app.jobs.JobListAdapter;
public class ListFragment extends Fragment {
private int pagePosition; //the fragments page in the pageview of the main activity
public static final class PageType {
public static final int COUNT = 3;
public static final int COUNT = 2;
public static final int EVENTS = 0;
public static final int NOTIFICATIONS = 1;
public static final int JOBS = 2;
public static final int JOBS = 1;
//public static final int NOTIFICATIONS = 2;
}
private RecyclerView recyclerView;
......@@ -45,29 +43,29 @@ public class ListFragment extends Fragment {
private RecyclerView.LayoutManager recyclerLayoutAdapter;
private SwipeRefreshLayout swipeRefreshLayout;
private Requests.OnDataReceivedCallback cancelRefreshCallback = new Requests.OnDataReceivedCallback() {
private Request.OnDataReceivedCallback cancelRefreshCallback = new Request.OnDataReceivedCallback() {
@Override
public void OnDataReceived() {
SetRefreshUI(false);
}
};
public Requests.OnDataReceivedCallback onEventsListUpdatedCallback = new Requests.OnDataReceivedCallback() {
public Request.OnDataReceivedCallback onEventsListUpdatedCallback = new Request.OnDataReceivedCallback() {
@Override
public void OnDataReceived() {
Requests.FetchEventSignups(MainActivity.instance, onSignupsUpdatedCallback, null, "");
Request.FetchEventSignups(MainActivity.instance, onSignupsUpdatedCallback, null, "");
RefreshList(true);
}
};
public Requests.OnDataReceivedCallback onJobsListUpdatedCallback = new Requests.OnDataReceivedCallback() {
public Request.OnDataReceivedCallback onJobsListUpdatedCallback = new Request.OnDataReceivedCallback() {
@Override
public void OnDataReceived() {
RefreshList(true);
}
};
private Requests.OnDataReceivedCallback onSignupsUpdatedCallback = new Requests.OnDataReceivedCallback() {
private Request.OnDataReceivedCallback onSignupsUpdatedCallback = new Request.OnDataReceivedCallback() {
@Override
public void OnDataReceived() {
RefreshList(false);
......@@ -187,9 +185,9 @@ public class ListFragment extends Fragment {
private void OnSwipeRefreshed(){
if(pagePosition == PageType.EVENTS)
Requests.FetchEventList(MainActivity.instance, onEventsListUpdatedCallback, cancelRefreshCallback, "");
Request.FetchEventList(MainActivity.instance, onEventsListUpdatedCallback, cancelRefreshCallback, "");
else if (pagePosition == PageType.JOBS)
Requests.FetchJobList(MainActivity.instance, onJobsListUpdatedCallback, cancelRefreshCallback, "");
Request.FetchJobList(MainActivity.instance, onJobsListUpdatedCallback, cancelRefreshCallback, "");
}
public void RefreshList(boolean animate)
......
......@@ -16,7 +16,6 @@ import android.widget.EditText;
import android.widget.TextView;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
......@@ -109,10 +108,11 @@ public class LoginActivity extends AppCompatActivity {
SetSubmitButtonState(false, true);
Settings.Vibrate(Settings.VibrateTime.NORMAL, getApplicationContext());
ReturnToCallingActivity(true, false);
return;
}
//Does a POST request to sessions to create a session and get a token. Does *not* use the OAuth process, see api docs
StringRequest request = new StringRequest(Request.Method.POST, Settings.API_URL + "sessions", null, null)
StringRequest request = new StringRequest(com.android.volley.Request.Method.POST, Settings.API_URL + "sessions", null, null)
{
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
......@@ -179,7 +179,7 @@ public class LoginActivity extends AppCompatActivity {
}
};
boolean wasSent = Requests.SendRequest(request, getApplicationContext());
boolean wasSent = Request.SendRequest(request, getApplicationContext());
if(wasSent)
SetSubmitButtonState(false, false);
else
......
......@@ -24,7 +24,6 @@ import android.widget.TextView;
import java.util.Vector;
import ch.amiv.android_app.R;
import ch.amiv.android_app.checkin.BarcodeIdActivity;
import ch.amiv.android_app.events.EventDetailActivity;
import ch.amiv.android_app.events.Events;
import ch.amiv.android_app.jobs.JobDetailActivity;
......@@ -38,7 +37,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
//region - ====Variables====
private NavigationView drawerNavigation;
private NavigationView drawerNav;
private TextView drawer_title;
private TextView drawer_subtitle;
......@@ -59,9 +58,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
case R.id.bottom_nav_events:
viewPager.setCurrentItem(ListFragment.PageType.EVENTS);
return true;
case R.id.bottom_nav_notifications:
/*case R.id.bottom_nav_notifications:
viewPager.setCurrentItem(ListFragment.PageType.NOTIFICATIONS);
return true;
return true;*/
case R.id.bottom_nav_jobs:
viewPager.setCurrentItem(ListFragment.PageType.JOBS);
return true;
......@@ -89,10 +88,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
drawer.addDrawerListener(toggle);
toggle.syncState();
drawerNavigation = findViewById(R.id.nav_view);
drawerNavigation.setNavigationItemSelectedListener(this);
drawer_title = drawerNavigation.getHeaderView(0).findViewById(R.id.drawer_user_title);
drawer_subtitle = drawerNavigation.getHeaderView(0).findViewById(R.id.drawer_user_subtitle);
drawerNav = findViewById(R.id.nav_view);
drawerNav.setNavigationItemSelectedListener(this);
drawer_title = drawerNav.getHeaderView(0).findViewById(R.id.drawer_user_title);
drawer_subtitle = drawerNav.getHeaderView(0).findViewById(R.id.drawer_user_subtitle);
bottomNavigation = findViewById(R.id.bottomNav);
bottomNavigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
......@@ -103,7 +102,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
//fetch the user info if we are logged in, there exists a token from the previous session, should be cached.
if(!PersistentStorage.LoadUserInfo(getApplicationContext()) || UserInfo.current._id.isEmpty() && !Settings.IsEmailOnlyLogin(getApplicationContext())) {
Requests.FetchUserData(getApplicationContext(), drawerNavigation, new Requests.OnDataReceivedCallback() {
Request.FetchUserData(getApplicationContext(), drawerNav, new Request.OnDataReceivedCallback() {
@Override
public void OnDataReceived() {
SetLoginUIDirty();
......@@ -136,8 +135,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
position = R.id.bottom_nav_events;
/*else if (position == 1)
position = R.id.bottom_nav_blitz;*/
else if (position == ListFragment.PageType.NOTIFICATIONS)
position = R.id.bottom_nav_notifications;
/*else if (position == ListFragment.PageType.NOTIFICATIONS)
position = R.id.bottom_nav_notifications;*/
else if (position == ListFragment.PageType.JOBS)
position = R.id.bottom_nav_jobs;
......@@ -161,7 +160,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
pagerAdapter.RefreshPage(ListFragment.PageType.EVENTS, true);
SetLoginUIDirty();
Requests.FetchEventList(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
Request.FetchEventList(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
}
/**
......@@ -170,7 +169,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
public void SetLoginUIDirty ()
{
if(Settings.IsLoggedIn(getApplicationContext())) {
drawerNavigation.getMenu().findItem(R.id.nav_login)
drawerNav.getMenu().findItem(R.id.nav_login)
.setTitle(R.string.logout_title)
.setChecked(false);
if(UserInfo.current != null)
......@@ -184,15 +183,19 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
drawer_subtitle.setText(UserInfo.current.email);
}
}
///else XXX
/// fetchuserinfo
}
else
{
drawerNavigation.getMenu().findItem(R.id.nav_login)
drawerNav.getMenu().findItem(R.id.nav_login)
.setTitle(R.string.login_title)
.setChecked(false);
drawer_title.setText(R.string.not_logged_in);
drawer_subtitle.setText("");
}
MicroApp.RefreshDrawer(this);
}
//endregion
......@@ -227,21 +230,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
startActivityForResult(intent, 0);
}
private void StartCheckinActivity() {
Intent intent = new Intent(this, ch.amiv.android_app.checkin.MainActivity.class);
startActivity(intent);
}
private void StartBarcodeIdActivity() {
Intent intent = new Intent(this, BarcodeIdActivity.class);
startActivity(intent);
}
/*private void StartDemoActivity() {
Intent intent = new Intent(this, ch.amiv.android_app.demo.MainActivity.class);
startActivity(intent);
}*/
/**
* Here we can interpret the result of the login/event detail activity, if the login was successful or not, then update accordingly
* @param requestCode
......@@ -256,15 +244,15 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
if(refreshLogin && Settings.IsLoggedIn(getApplicationContext()))
{
SetLoginUIDirty();
Requests.FetchUserData(getApplicationContext(), drawerNavigation, new Requests.OnDataReceivedCallback() {
Request.FetchUserData(getApplicationContext(), drawerNav, new Request.OnDataReceivedCallback() {
@Override
public void OnDataReceived() {
SetLoginUIDirty();
//Update events and signups with the new userinfo
if(Events.eventInfos.size() > 0)
Requests.FetchEventSignups(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
Request.FetchEventSignups(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
else
Requests.FetchEventList(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
Request.FetchEventList(getApplicationContext(), pages.get(ListFragment.PageType.EVENTS).onEventsListUpdatedCallback, null, "");
}
});
......@@ -280,6 +268,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
return super.onCreateOptionsMenu(menu);
}
/**
* Use this to add an option item (three dots on top right of actionBar)
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
......@@ -289,7 +280,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
//noinspection SimplifiableIfStatement
/*if (id == R.id.action_favorite) {
Requests.FetchEventList(getApplicationContext(), onEventsListUpdatedCallback, null);
Request.FetchEventList(getApplicationContext(), onEventsListUpdatedCallback, null);
return true;
}*/
......@@ -323,14 +314,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
else
StartLoginActivity();
}
else if (id == R.id.nav_checkin)
StartCheckinActivity();
else if (id == R.id.nav_barcode_id)
StartBarcodeIdActivity();
else if (id == R.id.nav_settings)
StartSettingsActivity();
/*else if(id == R.id.nav_demo)
StartDemoActivity();*/
//Note:microapp clicking is handled in MicroApp
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
......
package ch.amiv.android_app.core;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.support.design.widget.NavigationView;
import android.view.Menu;
import android.view.MenuItem;
import ch.amiv.android_app.R;
/**
* This class handles all microapps accessibly via the drawer in the MainActivity.
* To add your own:
* 1. add to the apps array and a unique int to the MicroAppPresets
* 2. Add a menu item to the core_ac_main_drawer.xml, there you can set the title (use a resource string) and its icon.
* For reference there is a commented out demo app
*/
public class MicroApp {
//This is the list of microapps, add yours here, then add its index to the MicroAppPresets for easy access to the data
public static MicroApp[] apps = {new MicroApp(UserInfo.AccessLevel.EMAIL, R.id.nav_checkin, ch.amiv.android_app.checkin.MainActivity.class),
new MicroApp(UserInfo.AccessLevel.EMAIL, R.id.nav_barcode_id, ch.amiv.android_app.checkin.BarcodeIdActivity.class)/*,
new MicroApp(UserInfo.AccessLevel.LOGIN, R.id.nav_demo, ch.amiv.android_app.demo.MainActivity.class)*/};
public static final class MicroAppPresets {
public static final int CHECKIN = 0;
public static final int BARCODE_ID = 1;
//public static final int DEMO = 2
}
public int accessLevel; //Use an UserInfo.AccessLevel
public int drawerMenuId; //The id of the menu in core_ac_main_drawer.xml
public Class<?> activityClass; //The class of your activity in the form MyActivity.class,
public MicroApp (int accessLevel_, int drawerMenuId_, Class<?> activityClass_){
accessLevel = accessLevel_;
drawerMenuId = drawerMenuId_;
activityClass = activityClass_;
}
/**
* Launches the microapp if the user is authorised
*/
public void LaunchApp (Context context){
if(!UserInfo.IsAuthorised(accessLevel, context))
return;
Intent intent = new Intent(context, activityClass);
context.startActivity(intent);
}
/**
* Will update the list of apps in the drawer accessible to the current user. Will only work in the MainActivity
*/
public static void RefreshDrawer(final Activity activity){
if(activity == null || !(activity instanceof MainActivity))
return;
NavigationView drawer = activity.findViewById(R.id.nav_view);
if(drawer == null)
return;
Menu menu = drawer.getMenu();
for (int i = 0; i < apps.length; i++){
if(apps[i] == null || apps[i].drawerMenuId == 0 || menu.findItem(apps[i].drawerMenuId) == null)
continue;
MenuItem menuItem = menu.findItem(apps[i].drawerMenuId);
boolean isVisible = UserInfo.IsAuthorised(apps[i].accessLevel, activity.getApplicationContext());
menuItem.setVisible(isVisible);
//Set to launch activity when clicked
final int index = i;
menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
MicroApp.apps[index].LaunchApp(activity.getApplicationContext());
return true;
}
});
}
}
}
......@@ -13,7 +13,6 @@ import android.view.View;
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
......@@ -49,7 +48,7 @@ import ch.amiv.android_app.jobs.Jobs;
*
* Libary used for network stuff: volley, note: we use our own modified version of the libary as a git submodule
*/
public final class Requests {
public final class Request {
private static RequestQueue requestQueue;
private static ImageLoader imageLoader;
private static final int MAX_CACHED_IMAGES = 75;
......@@ -70,7 +69,7 @@ public final class Requests {
* @param request A volley request of generic type, eg StringRequest, JsonRequest
* @return true if the request was sent successfully
*/
public static boolean SendRequest(Request request, Context context){
public static boolean SendRequest(com.android.volley.Request request, Context context){
if(!CheckConnection(context))
return false;
......@@ -95,11 +94,11 @@ public final class Requests {
}
String url = Settings.API_URL + "events" + (eventId.isEmpty() ?
(Settings.showHiddenFeatures ? "" : "?where={\"show_website\":true}")
(UserInfo.ShowHiddenFeatures(context) ? "" : "?where={\"show_website\":true}")
: "/" + eventId) ;
Log.e("request", "url: " + url);
StringRequest request = new StringRequest(Request.Method.GET, url,null, null)
StringRequest request = new StringRequest(com.android.volley.Request.Method.GET, url,null, null)
{
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) { //Note: the parseNetworkResponse is only called if the response was successful (codes 2xx), else parseNetworkError is called.
......@@ -169,7 +168,7 @@ public final class Requests {
};
//send the request and check if it failed
if(!Requests.SendRequest(request, context))
if(!Request.SendRequest(request, context))
RunCallback(errorCallback);
}
......@@ -187,7 +186,7 @@ public final class Requests {
String url = Settings.API_URL + "eventsignups?where={\"user\":\"" + UserInfo.current._id + "\"" + (eventId.isEmpty() ? "" : ",\"event\":\"" + eventId + "\"") + "}";
Log.e("request", "url: " + url);
StringRequest request = new StringRequest(Request.Method.GET, url,null, null)
StringRequest request = new StringRequest(com.android.volley.Request.Method.GET, url,null, null)
{
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) { //Note: the parseNetworkResponse is only called if the response was successful (codes 2xx), else parseNetworkError is called.
......@@ -248,7 +247,7 @@ public final class Requests {
}
};
if(!Requests.SendRequest(request, context))
if(!Request.SendRequest(request, context))
RunCallback(errorCallback);
}
......@@ -260,11 +259,11 @@ public final class Requests {
}
String url = Settings.API_URL + "joboffers" + (jobId.isEmpty() ?
(Settings.showHiddenFeatures ? "" : "?where={\"show_website\":true}")
(UserInfo.ShowHiddenFeatures(context) ? "" : "?where={\"show_website\":true}")
: "/" + jobId);
Log.e("request", "url: " + url);
StringRequest request = new StringRequest(Request.Method.GET, url,null, null)
StringRequest request = new StringRequest(com.android.volley.Request.Method.GET, url,null, null)
{
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) { //Note: the parseNetworkResponse is only called if the response was successful (codes 2xx), else parseNetworkError is called.
......@@ -334,7 +333,7 @@ public final class Requests {
};
//send the request and check if it failed
if(!Requests.SendRequest(request, context))
if(!Request.SendRequest(request, context))
RunCallback(errorCallback);
}
......@@ -348,7 +347,7 @@ public final class Requests {
//Do request Token->User
String url = Settings.API_URL + "sessions/" + Settings.GetToken(context) + "?embedded={\"user\":1}";
StringRequest request = new StringRequest(Request.Method.GET, url,null, null)
StringRequest request = new StringRequest(com.android.volley.Request.Method.GET, url,null, null)
{
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) { //Note: the parseNetworkResponse is only called if the response was successful (codes 2xx), else parseNetworkError is called.
......@@ -403,7 +402,7 @@ public final class Requests {
}
};
boolean hasSent = Requests.SendRequest(request, context);
boolean hasSent = Request.SendRequest(request, context);
}
/**
......@@ -416,7 +415,7 @@ public final class Requests {
//Do patch request to /user/{userId}
String url = Settings.API_URL + "users/" + UserInfo.current._id;
StringRequest request = new StringRequest(Request.Method.PATCH, url,null, null)
StringRequest request = new StringRequest(com.android.volley.Request.Method.PATCH, url,null, null)
{
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) { //Note: the parseNetworkResponse is only called if the response was successful (codes 2xx), else parseNetworkError is called.
......@@ -461,7 +460,7 @@ public final class Requests {
}
};
boolean hasSent = Requests.SendRequest(request, context);
boolean hasSent = Request.SendRequest(request, context);
}
/**
......@@ -482,7 +481,7 @@ public final class Requests {
//Do request Token->User
String url = Settings.API_URL + "sessions/" + user.session_id;
StringRequest request = new StringRequest(Request.Method.DELETE, url,null, null)
StringRequest request = new StringRequest(com.android.volley.Request.Method.DELETE, url,null, null)
{
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) { //Note: the parseNetworkResponse is only called if the response was successful (codes 2xx), else parseNetworkError is called.
......@@ -521,7 +520,7 @@ public final class Requests {
};
Settings.SetToken("", context);
Requests.SendRequest(request, context);
Request.SendRequest(request, context);
}
/**
......
......@@ -23,9 +23,6 @@ public class Settings {
//public static final String API_URL = "http://192.168.1.105:5000/";
public static final String API_URL = "https://api-dev.amiv.ethz.ch/";
//Whether to show hidden events, where the adverts should not have started yet, should later be set by user access group
public static final boolean showHiddenFeatures = true;
//---PREF KEYS---- Vars for saving/reading the url from shared prefs, to allow saving between sessions. For each variable, have a key to access it and a default value
private static SharedPreferences sharedPrefs;
public static final String SHARED_PREFS_KEY = "ch.amiv.android_app";
......@@ -125,8 +122,8 @@ public class Settings {
}
/**
* Note: will only check if a token exists. This token may have expired but not have been refreshed/deleted.
* @return True if the user is logged into the api and has an access token.
* Note: token may have expired but not have been refreshed/deleted.
* @return True if there is a token or an email login
*/
public static boolean IsLoggedIn(Context context){
return HasToken(context) || IsEmailOnlyLogin(context);
......
......@@ -4,6 +4,8 @@ import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import ch.amiv.android_app.BuildConfig;
/**
* This is the launcher/splash activity, here we choose to start the main activty or begin the setup process depending on whether the user has done the setup or not (stored in settings)
* For the UI we use a theme with the splash_screen, using a layout file is not possible as we have to display it while loading, need to use a basic xml, no inflation
......@@ -16,8 +18,9 @@ public class SplashActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
//DEBUG to access intro
Settings.ClearSharedPrefs(getApplicationContext());
//if(BuildConfig.DEBUG)
// Settings.ClearSharedPrefs(getApplicationContext());
Intent intent;
if(Settings.GetBoolPref(Settings.introDoneKey, getApplicationContext()))
......
......@@ -6,8 +6,6 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.io.Serializable;
import java.util.EmptyStackException;
import java.util.zip.CheckedOutputStream;
import ch.amiv.android_app.events.Events;
import ch.amiv.android_app.util.PersistentStorage;
......@@ -145,11 +143,57 @@ public class UserInfo implements Serializable{
}
else {
//delete session at the server and then clear the token
Requests.DeleteCurrentSession(context);
Request.DeleteCurrentSession(context);
Events.ClearSignups();
}
PersistentStorage.ClearUser(context);
UserInfo.current = null;
}
//region ---Access Level---
/**
* Use this to determine features only accessible to certain users
*/