Working Progress (not runnable)
This commit is contained in:
@@ -24,15 +24,6 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<provider
|
|
||||||
android:name="androidx.core.content.FileProvider"
|
|
||||||
android:authorities="${applicationId}.my.provider"
|
|
||||||
android:exported="false"
|
|
||||||
android:grantUriPermissions="true">
|
|
||||||
<meta-data
|
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
|
||||||
android:resource="@xml/provider_paths"/>
|
|
||||||
</provider>
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -33,16 +33,20 @@ import de.sebse.fuplanner.fragments.canteen.DaySwitcherFragment;
|
|||||||
import de.sebse.fuplanner.fragments.moddetails.ModDetailFragment;
|
import de.sebse.fuplanner.fragments.moddetails.ModDetailFragment;
|
||||||
import de.sebse.fuplanner.services.Canteen.CanteenBrowser;
|
import de.sebse.fuplanner.services.Canteen.CanteenBrowser;
|
||||||
import de.sebse.fuplanner.services.Canteen.types.Canteen;
|
import de.sebse.fuplanner.services.Canteen.types.Canteen;
|
||||||
|
import de.sebse.fuplanner.services.GoogleAuth.Credentials;
|
||||||
import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth;
|
import de.sebse.fuplanner.services.GoogleAuth.GoogleAuth;
|
||||||
import de.sebse.fuplanner.services.KVV.KVV;
|
import de.sebse.fuplanner.services.NewKVV.KVV;
|
||||||
import de.sebse.fuplanner.services.KVV.types.LoginToken;
|
import de.sebse.fuplanner.services.KVV.types.LoginToken;
|
||||||
import de.sebse.fuplanner.services.KVV.types.Modules;
|
import de.sebse.fuplanner.services.NewKVV.KVVListener;
|
||||||
import de.sebse.fuplanner.tools.MainActivityListener;
|
import de.sebse.fuplanner.tools.MainActivityListener;
|
||||||
import de.sebse.fuplanner.tools.RequestPermissionsResultListener;
|
import de.sebse.fuplanner.tools.RequestPermissionsResultListener;
|
||||||
import de.sebse.fuplanner.tools.logging.Logger;
|
import de.sebse.fuplanner.tools.logging.Logger;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity
|
public class MainActivity extends AppCompatActivity
|
||||||
implements MainActivityListener,
|
implements MainActivityListener, KVVListener,
|
||||||
NavigationView.OnNavigationItemSelectedListener,
|
NavigationView.OnNavigationItemSelectedListener,
|
||||||
LoginFragment.OnLoginFragmentInteractionListener,
|
LoginFragment.OnLoginFragmentInteractionListener,
|
||||||
ModulesFragment.OnModulesFragmentInteractionListener,
|
ModulesFragment.OnModulesFragmentInteractionListener,
|
||||||
@@ -63,26 +67,25 @@ public class MainActivity extends AppCompatActivity
|
|||||||
|
|
||||||
private FragmentManager mFragmentManager;
|
private FragmentManager mFragmentManager;
|
||||||
private GoogleAuth mGoogleAuth;
|
private GoogleAuth mGoogleAuth;
|
||||||
private KVV mKVV;
|
private de.sebse.fuplanner.services.KVV.KVV mKVV;
|
||||||
|
private KVV mNewKVV;
|
||||||
private final Logger log = new Logger(this);
|
private final Logger log = new Logger(this);
|
||||||
private NavigationView mNavigationView;
|
private NavigationView mNavigationView;
|
||||||
|
|
||||||
private int fragmentPage = FRAGMENT_NONE;
|
private int fragmentPage = FRAGMENT_NONE;
|
||||||
private int currentPage = FRAGMENT_NONE;
|
|
||||||
private String fragmentData = "";
|
private String fragmentData = "";
|
||||||
private String currentData = "";
|
|
||||||
private CanteenBrowser mCanteenBrowser;
|
private CanteenBrowser mCanteenBrowser;
|
||||||
private boolean mOfflineMode = false;
|
|
||||||
private HashMap<String, RequestPermissionsResultListener> permissionListeners = new HashMap<>();
|
private HashMap<String, RequestPermissionsResultListener> permissionListeners = new HashMap<>();
|
||||||
|
private boolean mOfflineBanner;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
int newFragmentPage = FRAGMENT_NONE;
|
int desiredPage = getDefaultFragmentAfterLogin();
|
||||||
String newFragmentData = "";
|
String desiredData = "";
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
newFragmentPage = savedInstanceState.getInt(ARG_FRAGMENT_PAGE, fragmentPage);
|
desiredPage = savedInstanceState.getInt(ARG_FRAGMENT_PAGE, desiredPage);
|
||||||
newFragmentData = savedInstanceState.getString(ARG_FRAGMENT_STATUS, fragmentData);
|
desiredData = savedInstanceState.getString(ARG_FRAGMENT_STATUS, desiredData);
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
@@ -99,15 +102,9 @@ public class MainActivity extends AppCompatActivity
|
|||||||
mNavigationView.setNavigationItemSelectedListener(this);
|
mNavigationView.setNavigationItemSelectedListener(this);
|
||||||
mFragmentManager = getSupportFragmentManager();
|
mFragmentManager = getSupportFragmentManager();
|
||||||
|
|
||||||
LoginToken loginToken = getKVV().easyLogin();
|
getNewKVV().account().doOfflineLogin();
|
||||||
if (loginToken == null) {
|
updateNavigation();
|
||||||
checkAndDoLogin();
|
changeFragment(desiredPage, desiredData);
|
||||||
} else {
|
|
||||||
if (newFragmentPage != FRAGMENT_LOGIN && newFragmentPage != FRAGMENT_STARTUP && newFragmentPage != FRAGMENT_NONE)
|
|
||||||
toLoginState(loginToken, newFragmentPage, newFragmentData);
|
|
||||||
else
|
|
||||||
toLoginState(loginToken, getDefaultFragmentAfterLogin(), "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -123,7 +120,7 @@ public class MainActivity extends AppCompatActivity
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
if (currentPage == FRAGMENT_SCHEDULE) {
|
if (fragmentPage == FRAGMENT_SCHEDULE) {
|
||||||
getMenuInflater().inflate(R.menu.options_schedule, menu);
|
getMenuInflater().inflate(R.menu.options_schedule, menu);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -180,13 +177,13 @@ public class MainActivity extends AppCompatActivity
|
|||||||
startActivity(sendIntent);
|
startActivity(sendIntent);
|
||||||
break;
|
break;
|
||||||
case R.id.nav_logout:
|
case R.id.nav_logout:
|
||||||
this.getKVV().logout();
|
getNewKVV().account().logout(true);
|
||||||
this.getGoogleAuth().getLoginState(credentials -> {
|
this.getGoogleAuth().getLoginState(credentials -> {
|
||||||
if (credentials != null) {
|
if (credentials != null) {
|
||||||
this.getGoogleAuth().deleteLoginState(credentials.getUsername(), credentials.getPassword());
|
this.getGoogleAuth().deleteLoginState(credentials.getUsername(), credentials.getPassword());
|
||||||
}
|
}
|
||||||
this.toLogoutState();
|
|
||||||
});
|
});
|
||||||
|
this.toLogoutState();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -210,13 +207,14 @@ public class MainActivity extends AppCompatActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(Bundle savedInstanceState) {
|
protected void onSaveInstanceState(Bundle savedInstanceState) {
|
||||||
Fragment fragment = mFragmentManager.findFragmentByTag(String.valueOf(fragmentPage));
|
if (fragmentPage != FRAGMENT_STARTUP && fragmentPage != FRAGMENT_NONE && fragmentPage != FRAGMENT_LOGIN) {
|
||||||
savedInstanceState.putInt(ARG_FRAGMENT_PAGE, fragmentPage);
|
Fragment fragment = mFragmentManager.findFragmentByTag(String.valueOf(fragmentPage));
|
||||||
savedInstanceState.putString(ARG_FRAGMENT_STATUS, fragmentData);
|
savedInstanceState.putInt(ARG_FRAGMENT_PAGE, fragmentPage);
|
||||||
if (fragment instanceof ModDetailFragment) {
|
if (fragment instanceof ModDetailFragment) {
|
||||||
savedInstanceState.putString(ARG_FRAGMENT_STATUS, ((ModDetailFragment) fragment).getData());
|
savedInstanceState.putString(ARG_FRAGMENT_STATUS, ((ModDetailFragment) fragment).getData());
|
||||||
} else {
|
} else {
|
||||||
savedInstanceState.putString(ARG_FRAGMENT_STATUS, fragmentData);
|
savedInstanceState.putString(ARG_FRAGMENT_STATUS, fragmentData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.onSaveInstanceState(savedInstanceState);
|
super.onSaveInstanceState(savedInstanceState);
|
||||||
}
|
}
|
||||||
@@ -239,13 +237,21 @@ public class MainActivity extends AppCompatActivity
|
|||||||
return this.mGoogleAuth;
|
return this.mGoogleAuth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KVV getKVV() {
|
@Deprecated
|
||||||
|
public de.sebse.fuplanner.services.KVV.KVV getKVV() {
|
||||||
if (this.mKVV == null) {
|
if (this.mKVV == null) {
|
||||||
this.mKVV = new KVV(this);
|
this.mKVV = new de.sebse.fuplanner.services.KVV.KVV(this);
|
||||||
}
|
}
|
||||||
return this.mKVV;
|
return this.mKVV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KVV getNewKVV() {
|
||||||
|
if (this.mNewKVV == null) {
|
||||||
|
this.mNewKVV = new KVV(this, this);
|
||||||
|
}
|
||||||
|
return this.mNewKVV;
|
||||||
|
}
|
||||||
|
|
||||||
public CanteenBrowser getCanteenBrowser() {
|
public CanteenBrowser getCanteenBrowser() {
|
||||||
if (this.mCanteenBrowser == null) {
|
if (this.mCanteenBrowser == null) {
|
||||||
this.mCanteenBrowser = new CanteenBrowser(this);
|
this.mCanteenBrowser = new CanteenBrowser(this);
|
||||||
@@ -254,23 +260,13 @@ public class MainActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getDefaultFragmentAfterLogin() {
|
private int getDefaultFragmentAfterLogin() {
|
||||||
return getDefaultFragmentAfterLogin(new String[1]);
|
return FRAGMENT_MODULES;
|
||||||
}
|
|
||||||
|
|
||||||
private int getDefaultFragmentAfterLogin(String[] id) {
|
|
||||||
if (fragmentPage == FRAGMENT_NONE){
|
|
||||||
id[0] = "";
|
|
||||||
return FRAGMENT_MODULES;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
id[0] = fragmentData;
|
|
||||||
return fragmentPage;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toLogoutState() {
|
private void toLogoutState() {
|
||||||
setOfflineBanner(true);
|
setOfflineBanner(false);
|
||||||
setRefreshFailedBanner(false);
|
setRefreshFailedBanner(false);
|
||||||
|
updateNavigation();
|
||||||
changeFragment(FRAGMENT_LOGIN);
|
changeFragment(FRAGMENT_LOGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,14 +279,17 @@ public class MainActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void toLoginState(String fullName, String email, int newFragment, String newData, boolean onlineMode) {
|
private void toLoginState(String fullName, String email, int newFragment, String newData, boolean onlineMode) {
|
||||||
setOfflineBanner(onlineMode);
|
setOfflineBanner(!onlineMode);
|
||||||
changeFragment(newFragment, newData);
|
updateNavigation();
|
||||||
|
|
||||||
View header = mNavigationView.getHeaderView(0);
|
View header = mNavigationView.getHeaderView(0);
|
||||||
((TextView) header.findViewById(R.id.login_name)).setText(fullName);
|
((TextView) header.findViewById(R.id.login_name)).setText(fullName);
|
||||||
((TextView) header.findViewById(R.id.login_mail)).setText(email);
|
((TextView) header.findViewById(R.id.login_mail)).setText(email);
|
||||||
|
|
||||||
|
changeFragment(newFragment, newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
private void checkAndDoLogin() {
|
private void checkAndDoLogin() {
|
||||||
changeFragment(FRAGMENT_STARTUP);
|
changeFragment(FRAGMENT_STARTUP);
|
||||||
getGoogleAuth().getLoginState(credentials -> {
|
getGoogleAuth().getLoginState(credentials -> {
|
||||||
@@ -298,10 +297,9 @@ public class MainActivity extends AppCompatActivity
|
|||||||
toLogoutState();
|
toLogoutState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String[] id = {""};
|
|
||||||
|
|
||||||
int fragment = getDefaultFragmentAfterLogin(id);
|
int fragment = getDefaultFragmentAfterLogin();
|
||||||
this.getKVV().login(credentials.getUsername(), credentials.getPassword(), success -> toLoginState(success, fragment , id[0]),
|
this.getKVV().login(credentials.getUsername(), credentials.getPassword(), success -> toLoginState(success, fragment, ""),
|
||||||
error -> {
|
error -> {
|
||||||
log.e(error);
|
log.e(error);
|
||||||
toLogoutState();
|
toLogoutState();
|
||||||
@@ -355,56 +353,38 @@ public class MainActivity extends AppCompatActivity
|
|||||||
fragmentTransaction.commit();
|
fragmentTransaction.commit();
|
||||||
|
|
||||||
if (newFragment == FRAGMENT_STARTUP) {
|
if (newFragment == FRAGMENT_STARTUP) {
|
||||||
findViewById(R.id.app_bar_layout).setVisibility(View.GONE);
|
findViewById(R.id.app_bar_include).setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
findViewById(R.id.app_bar_layout).setVisibility(View.VISIBLE);
|
findViewById(R.id.app_bar_include).setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isChangeLoginState =
|
this.fragmentPage = newFragment;
|
||||||
(
|
this.fragmentData = newData;
|
||||||
(newFragment == FRAGMENT_STARTUP || newFragment == FRAGMENT_LOGIN) &&
|
|
||||||
(currentPage != FRAGMENT_STARTUP && currentPage != FRAGMENT_LOGIN)
|
|
||||||
) || (
|
|
||||||
(currentPage == FRAGMENT_STARTUP || currentPage == FRAGMENT_LOGIN || currentPage == FRAGMENT_NONE) &&
|
|
||||||
(newFragment != FRAGMENT_STARTUP && newFragment != FRAGMENT_LOGIN && (getKVV().isLoggedIn() || mOfflineMode))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (newFragment != FRAGMENT_STARTUP && newFragment != FRAGMENT_NONE && newFragment != FRAGMENT_LOGIN) {
|
|
||||||
this.fragmentPage = newFragment;
|
|
||||||
this.fragmentData = newData;
|
|
||||||
}
|
|
||||||
this.currentPage = newFragment;
|
|
||||||
this.currentData = newData;
|
|
||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
if (isChangeLoginState)
|
//TODO navigation selection
|
||||||
refreshNavigation();
|
|
||||||
else
|
|
||||||
setNavigationSelection(currentPage, currentData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setOfflineBanner(boolean onlineMode) {
|
private void setOfflineBanner(boolean visible) {
|
||||||
View offline_header = findViewById(R.id.offline_msg);
|
View offline_header = findViewById(R.id.offline_msg);
|
||||||
if (onlineMode)
|
offline_header.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||||
offline_header.setVisibility(View.GONE);
|
mOfflineBanner = visible;
|
||||||
else
|
|
||||||
offline_header.setVisibility(View.VISIBLE);
|
|
||||||
mOfflineMode = !onlineMode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setRefreshFailedBanner(boolean refreshFailed) {
|
private void setRefreshFailedBanner(boolean refreshFailed) {
|
||||||
View viewNoConnection = findViewById(R.id.no_connection_msg);
|
View viewNoConnection = findViewById(R.id.no_connection_msg);
|
||||||
if (!mOfflineMode && refreshFailed)
|
if (!mOfflineBanner && refreshFailed)
|
||||||
viewNoConnection.setVisibility(View.VISIBLE);
|
viewNoConnection.setVisibility(View.VISIBLE);
|
||||||
else
|
else
|
||||||
viewNoConnection.setVisibility(View.GONE);
|
viewNoConnection.setVisibility(View.GONE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setNavigationSelection(int fragment, String data) {
|
private void setNavigationSelection() {
|
||||||
MenuItem item;
|
MenuItem item;
|
||||||
switch (fragment) {
|
switch (fragmentPage) {
|
||||||
case FRAGMENT_MODULES_DETAILS:
|
case FRAGMENT_MODULES_DETAILS:
|
||||||
getKVV().getModule(data, success -> {
|
getKVV().getModule(fragmentData, success -> {
|
||||||
int size = mNavigationView.getMenu().size();
|
int size = mNavigationView.getMenu().size();
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
String title = success == null ? null : success.title;
|
String title = success == null ? null : success.title;
|
||||||
@@ -426,7 +406,7 @@ public class MainActivity extends AppCompatActivity
|
|||||||
case FRAGMENT_CANTEENS_DETAILS:
|
case FRAGMENT_CANTEENS_DETAILS:
|
||||||
getCanteenBrowser().getCanteens(success -> {
|
getCanteenBrowser().getCanteens(success -> {
|
||||||
int size = mNavigationView.getMenu().size();
|
int size = mNavigationView.getMenu().size();
|
||||||
Canteen canteen = success.getCanteen(Integer.parseInt(data));
|
Canteen canteen = success.getCanteen(Integer.parseInt(fragmentData));
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
String title = canteen == null ? null : canteen.getName();
|
String title = canteen == null ? null : canteen.getName();
|
||||||
for (int k = 0; k < size; k++) {
|
for (int k = 0; k < size; k++) {
|
||||||
@@ -466,10 +446,10 @@ public class MainActivity extends AppCompatActivity
|
|||||||
|
|
||||||
private void afterAnyMenuInflate(boolean isLoggedIn) {
|
private void afterAnyMenuInflate(boolean isLoggedIn) {
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
getKVV().getModuleList(success -> {
|
getNewKVV().modules().list().recv(success -> {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Iterator<Modules.Module> it = success.latestSemesterIterator(); it.hasNext(); ) {
|
for (Iterator<de.sebse.fuplanner.services.NewKVV.types.Modules.Module> it = success.latestSemesterIterator(); it.hasNext(); ) {
|
||||||
Modules.Module module = it.next();
|
de.sebse.fuplanner.services.NewKVV.types.Modules.Module module = it.next();
|
||||||
MenuItem menuItem = mNavigationView.getMenu().add(Menu.NONE, Menu.NONE, 101 + i, module.title);
|
MenuItem menuItem = mNavigationView.getMenu().add(Menu.NONE, Menu.NONE, 101 + i, module.title);
|
||||||
menuItem.setOnMenuItemClickListener(item -> {
|
menuItem.setOnMenuItemClickListener(item -> {
|
||||||
onModulesFragmentInteraction(module.getID());
|
onModulesFragmentInteraction(module.getID());
|
||||||
@@ -492,16 +472,30 @@ public class MainActivity extends AppCompatActivity
|
|||||||
}, log::e);
|
}, log::e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateNavigation() {
|
||||||
|
boolean isLoggedIn = getNewKVV().account().isLoggedIn();
|
||||||
|
setNavigationHeader(isLoggedIn);
|
||||||
|
mNavigationView.getMenu().clear();
|
||||||
|
if (isLoggedIn)
|
||||||
|
mNavigationView.inflateMenu(R.menu.activity_main_drawer_login);
|
||||||
|
else
|
||||||
|
mNavigationView.inflateMenu(R.menu.activity_main_drawer);
|
||||||
|
afterAnyMenuInflate(isLoggedIn);
|
||||||
|
setNavigationSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
public void onLoginFragmentInteraction(LoginToken loginToken, boolean onlineMode) {
|
public void onLoginFragmentInteraction(LoginToken loginToken, boolean onlineMode) {
|
||||||
String[] id = {""};
|
int fragment = getDefaultFragmentAfterLogin();
|
||||||
int fragment = getDefaultFragmentAfterLogin(id);
|
toLoginState(loginToken.getFullName(), loginToken.getEmail(), fragment, "", onlineMode);
|
||||||
toLoginState(loginToken.getFullName(), loginToken.getEmail(), fragment, id[0], onlineMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -524,6 +518,7 @@ public class MainActivity extends AppCompatActivity
|
|||||||
setTitle(titleId);
|
setTitle(titleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public void loginTokenInvalid(boolean doLoginCheck) {
|
public void loginTokenInvalid(boolean doLoginCheck) {
|
||||||
if (doLoginCheck) {
|
if (doLoginCheck) {
|
||||||
@@ -564,16 +559,33 @@ public class MainActivity extends AppCompatActivity
|
|||||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refreshNavigation() {
|
public void getCredentials(NetworkCallback<Credentials> callback, NetworkErrorCallback error) {
|
||||||
boolean isLoggedIn = getKVV().isLoggedIn() || mOfflineMode;
|
getGoogleAuth().getLoginState(credentials -> {
|
||||||
setNavigationHeader(isLoggedIn);
|
if (credentials == null || credentials.getUsername() == null || credentials.getPassword() == null) {
|
||||||
mNavigationView.getMenu().clear();
|
error.onError(new NetworkError(200100, 403, "No Google Login available!"));
|
||||||
if (isLoggedIn)
|
} else {
|
||||||
mNavigationView.inflateMenu(R.menu.activity_main_drawer_login);
|
callback.onResponse(credentials);
|
||||||
else
|
}
|
||||||
mNavigationView.inflateMenu(R.menu.activity_main_drawer);
|
});
|
||||||
afterAnyMenuInflate(isLoggedIn);
|
}
|
||||||
setNavigationSelection(currentPage, currentData);
|
|
||||||
|
@Override
|
||||||
|
public void handleLogin(de.sebse.fuplanner.services.NewKVV.types.LoginToken token, boolean enteringOnlineMode) {
|
||||||
|
toLoginState(token.getUsername(), token.getEmail(), getDefaultFragmentAfterLogin(), "", enteringOnlineMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleLogout() {
|
||||||
|
toLogoutState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,9 +117,9 @@ public class ModDetailAnnounceFragment extends Fragment implements Download.OnDo
|
|||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
if (context instanceof MainActivityListener) {
|
if (context instanceof MainActivityListener) {
|
||||||
this.context = ((MainActivityListener) context);
|
this.context = ((MainActivityListener) context);
|
||||||
this.context.addRequestPermissionsResultListener(getDownload().getRequestPermissionsResultListener(), "ModDetailResourceFragment");
|
this.context.addRequestPermissionsResultListener(getDownload().getRequestPermissionsResultListener(), "ModDetailAnnounceFragment");
|
||||||
} else
|
} else
|
||||||
throw new RuntimeException(context.toString() + " must implement MainActivityListener");
|
throw new RuntimeException(context.toString() + " must implement ModDetailAnnounceFragment");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public class ModDetailAssignmentFragment extends Fragment implements Download.On
|
|||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
if (context instanceof MainActivityListener) {
|
if (context instanceof MainActivityListener) {
|
||||||
this.context = ((MainActivityListener) context);
|
this.context = ((MainActivityListener) context);
|
||||||
this.context.addRequestPermissionsResultListener(getDownload().getRequestPermissionsResultListener(), "ModDetailResourceFragment");
|
this.context.addRequestPermissionsResultListener(getDownload().getRequestPermissionsResultListener(), "ModDetailAssignmentFragment");
|
||||||
} else
|
} else
|
||||||
throw new RuntimeException(context.toString() + " must implement MainActivityListener");
|
throw new RuntimeException(context.toString() + " must implement MainActivityListener");
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ public class ModDetailAssignmentFragment extends Fragment implements Download.On
|
|||||||
@Override
|
@Override
|
||||||
public void onDetach() {
|
public void onDetach() {
|
||||||
super.onDetach();
|
super.onDetach();
|
||||||
this.context.removeRequestPermissionsResultListener("ModDetailResourceFragment");
|
this.context.removeRequestPermissionsResultListener("ModDetailAssignmentFragment");
|
||||||
}
|
}
|
||||||
|
|
||||||
Download getDownload() {
|
Download getDownload() {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class GoogleAuth {
|
|||||||
|
|
||||||
private static final String TAG = "GoogleAuth";
|
private static final String TAG = "GoogleAuth";
|
||||||
private final FragmentActivity activity;
|
private final FragmentActivity activity;
|
||||||
|
private static final String FU_PLANNER_PROVIDER = "FUPlanner";
|
||||||
private CredentialsClient mCredentialsClient;
|
private CredentialsClient mCredentialsClient;
|
||||||
private boolean mIsResolving;
|
private boolean mIsResolving;
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -61,6 +62,7 @@ public class GoogleAuth {
|
|||||||
connect();
|
connect();
|
||||||
CredentialRequest request = new CredentialRequest.Builder()
|
CredentialRequest request = new CredentialRequest.Builder()
|
||||||
.setPasswordLoginSupported(true)
|
.setPasswordLoginSupported(true)
|
||||||
|
.setAccountTypes(FU_PLANNER_PROVIDER)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.FileProvider;
|
|
||||||
import de.sebse.fuplanner.MainActivity;
|
import de.sebse.fuplanner.MainActivity;
|
||||||
import de.sebse.fuplanner.R;
|
import de.sebse.fuplanner.R;
|
||||||
import de.sebse.fuplanner.services.KVV.types.Resource;
|
import de.sebse.fuplanner.services.KVV.types.Resource;
|
||||||
@@ -24,10 +23,7 @@ import de.sebse.fuplanner.tools.RequestPermissionsResultListener;
|
|||||||
import de.sebse.fuplanner.tools.UtilsDate;
|
import de.sebse.fuplanner.tools.UtilsDate;
|
||||||
import de.sebse.fuplanner.tools.logging.Logger;
|
import de.sebse.fuplanner.tools.logging.Logger;
|
||||||
|
|
||||||
import static android.content.Intent.normalizeMimeType;
|
|
||||||
import static androidx.core.app.ActivityCompat.startActivityForResult;
|
|
||||||
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
import static androidx.core.content.ContextCompat.checkSelfPermission;
|
||||||
import static androidx.core.content.ContextCompat.startActivity;
|
|
||||||
|
|
||||||
public class Download {
|
public class Download {
|
||||||
|
|
||||||
@@ -35,7 +31,6 @@ public class Download {
|
|||||||
private final ActivityInterface activityInterface;
|
private final ActivityInterface activityInterface;
|
||||||
private RequestedDownload requestedDownload;
|
private RequestedDownload requestedDownload;
|
||||||
private Logger log = new Logger(this);
|
private Logger log = new Logger(this);
|
||||||
static final int REQUEST_IMAGE_OPEN = 1;
|
|
||||||
|
|
||||||
|
|
||||||
public Download(ContextInterface contextInterface, ActivityInterface activityInterface) {
|
public Download(ContextInterface contextInterface, ActivityInterface activityInterface) {
|
||||||
@@ -60,7 +55,7 @@ public class Download {
|
|||||||
if (file.getModifiedDate() != 0) {
|
if (file.getModifiedDate() != 0) {
|
||||||
if (!message.isEmpty())
|
if (!message.isEmpty())
|
||||||
message += "\n";
|
message += "\n";
|
||||||
message += resources.getString(R.string.last_modified_on, UtilsDate.getModifiedDateTime(contextInterface.get(), file.getModifiedDate()));
|
resources.getString(R.string.last_modified_on, UtilsDate.getModifiedDateTime(contextInterface.get(), file.getModifiedDate()));
|
||||||
}
|
}
|
||||||
|
|
||||||
alertDialogBuilder
|
alertDialogBuilder
|
||||||
@@ -186,17 +181,9 @@ public class Download {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void fileOpen(File url){
|
private void fileOpen(File url){
|
||||||
|
Uri uri = Uri.fromFile(url);
|
||||||
|
|
||||||
Uri uri = FileProvider.getUriForFile(contextInterface.get(), contextInterface.get().getApplicationContext().getPackageName() + ".my.provider", url);
|
Intent intent = new Intent();//Intent.ACTION_VIEW
|
||||||
|
|
||||||
Intent intent;
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
|
|
||||||
intent = new Intent(Intent.ACTION_VIEW);
|
|
||||||
} else {
|
|
||||||
intent = new Intent();
|
|
||||||
}
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
||||||
// Check what kind of file you are trying to open, by comparing the url with extensions.
|
// Check what kind of file you are trying to open, by comparing the url with extensions.
|
||||||
// When the if condition is matched, plugin sets the correct intent (mime) type,
|
// When the if condition is matched, plugin sets the correct intent (mime) type,
|
||||||
// so Android knew what application to use to open the file
|
// so Android knew what application to use to open the file
|
||||||
@@ -235,18 +222,13 @@ public class Download {
|
|||||||
intent.setDataAndType(uri, "video/*");
|
intent.setDataAndType(uri, "video/*");
|
||||||
} else {
|
} else {
|
||||||
//if you want you can also define the intent type for any other file
|
//if you want you can also define the intent type for any other file
|
||||||
|
|
||||||
//additionally use else clause below, to manage other unknown extensions
|
//additionally use else clause below, to manage other unknown extensions
|
||||||
//in this case, Android will show all applications installed on the device
|
//in this case, Android will show all applications installed on the device
|
||||||
//so you can choose which application to use
|
//so you can choose which application to use
|
||||||
intent.setDataAndType(uri, "*/*");
|
intent.setDataAndType(uri, "*/*");
|
||||||
}
|
}
|
||||||
|
|
||||||
//intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
||||||
// Only the system receives the ACTION_OPEN_DOCUMENT, so no need to test.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
contextInterface.get().startActivity(intent);
|
contextInterface.get().startActivity(intent);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class KVV {
|
||||||
|
private final HashMap<String, Object> addons = new HashMap<>();
|
||||||
|
private final KVVListener mListener;
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
public KVV(KVVListener listener, Context context) {
|
||||||
|
this.mListener = listener;
|
||||||
|
this.mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public KVVLogin account() {
|
||||||
|
return (KVVLogin) addAndGet("account", () -> new KVVLogin(mListener, mContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public KVVModules modules() {
|
||||||
|
return (KVVModules) addAndGet("module", () -> new KVVModules(account(), mContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Object addAndGet(@NotNull String addon, @NotNull ModuleCreatorInterface creatorInterface) {
|
||||||
|
Object o = addons.get(addon);
|
||||||
|
if (o == null) {
|
||||||
|
o = creatorInterface.create();
|
||||||
|
addons.put(addon, o);
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface ModuleCreatorInterface {
|
||||||
|
@NotNull Object create();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.services.GoogleAuth.Credentials;
|
||||||
|
import de.sebse.fuplanner.services.NewKVV.types.LoginToken;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||||
|
|
||||||
|
public interface KVVListener {
|
||||||
|
void getCredentials(NetworkCallback<Credentials> callback, NetworkErrorCallback error);
|
||||||
|
|
||||||
|
void handleLogin(LoginToken token, boolean enteringOnlineMode);
|
||||||
|
|
||||||
|
void handleLogout();
|
||||||
|
}
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import de.sebse.fuplanner.services.NewKVV.types.LoginToken;
|
||||||
|
import de.sebse.fuplanner.tools.network.HTTPService;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||||
|
|
||||||
|
public class KVVLogin extends HTTPService {
|
||||||
|
private KVVListener mListener;
|
||||||
|
@Nullable private LoginToken mToken;
|
||||||
|
private boolean mLoginPending = false;
|
||||||
|
private boolean mOnlineMode = false;
|
||||||
|
|
||||||
|
KVVLogin(KVVListener listener, Context context) {
|
||||||
|
super(context);
|
||||||
|
this.mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doOnlineLogin(String username, String password, NetworkCallback<LoginToken> callback, NetworkErrorCallback errorCallback) {
|
||||||
|
if (mLoginPending) {
|
||||||
|
errorCallback.onError(new NetworkError(100160, -1, "Login already pending!"));
|
||||||
|
}
|
||||||
|
if (mToken != null) {
|
||||||
|
errorCallback.onError(new NetworkError(100161, -1, "Already logged in!"));
|
||||||
|
}
|
||||||
|
mLoginPending = true;
|
||||||
|
doLogin(username, password, token -> {
|
||||||
|
testLoginToken(token2 -> {
|
||||||
|
setToken(token, true);
|
||||||
|
mLoginPending = false;
|
||||||
|
callback.onResponse(token);
|
||||||
|
}, error -> {
|
||||||
|
mLoginPending = false;
|
||||||
|
errorCallback.onError(error);
|
||||||
|
});
|
||||||
|
}, error -> {
|
||||||
|
mLoginPending = false;
|
||||||
|
errorCallback.onError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean doOfflineLogin() {
|
||||||
|
if (mLoginPending || mToken != null)
|
||||||
|
return false;
|
||||||
|
mLoginPending = true;
|
||||||
|
boolean result = false;
|
||||||
|
try {
|
||||||
|
result = setToken(LoginToken.load(getContext()), false);
|
||||||
|
} catch (FileNotFoundException ignored) {
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
mLoginPending = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOfflineStoredAvailable() {
|
||||||
|
try {
|
||||||
|
LoginToken.load(getContext());
|
||||||
|
return true;
|
||||||
|
} catch (FileNotFoundException ignored) {
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean logout(boolean delete) {
|
||||||
|
if (mLoginPending)
|
||||||
|
return false;
|
||||||
|
if (mToken == null)
|
||||||
|
return true;
|
||||||
|
if (delete)
|
||||||
|
mToken.delete(getContext());
|
||||||
|
mToken = null;
|
||||||
|
return handleCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoginPending() {
|
||||||
|
return mLoginPending;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoggedIn() {
|
||||||
|
return mToken != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInOfflineMode() {
|
||||||
|
return isLoggedIn() && !mOnlineMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInOnlineMode() {
|
||||||
|
return isLoggedIn() && mOnlineMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLoginToken(NetworkCallback<LoginToken> callback, NetworkErrorCallback errorCallback) {
|
||||||
|
if (mToken == null) {
|
||||||
|
errorCallback.onError(new NetworkError(100173, -1, "Not logged in!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
get(String.format("https://kvv.imp.fu-berlin.de/direct/profile/%s.json", mToken.getUsername()), mToken.getCookies(), response -> {
|
||||||
|
String body = response.getParsed();
|
||||||
|
if (body == null) {
|
||||||
|
errorCallback.onError(new NetworkError(100172, 403, "Testing login failed!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
JSONObject json = new JSONObject(body);
|
||||||
|
String displayName = json.getString("displayName");
|
||||||
|
String email = json.getString("email");
|
||||||
|
mToken.setAdditionals(displayName, email);
|
||||||
|
callback.onResponse(mToken);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
errorCallback.onError(new NetworkError(100171, 403, "Cannot parse profile!"));
|
||||||
|
}
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(100170, error.networkResponse.statusCode, "Testing login failed!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable public LoginToken getLoginToken() {
|
||||||
|
return mToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshLogin(NetworkCallback<LoginToken> success, NetworkErrorCallback error) {
|
||||||
|
mListener.getCredentials(credentials -> {
|
||||||
|
doOnlineLogin(credentials.getUsername(), credentials.getPassword(), success, error);
|
||||||
|
}, e -> {
|
||||||
|
logout(false);
|
||||||
|
error.onError(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private boolean handleCallbacks() {
|
||||||
|
if (mToken != null) {
|
||||||
|
mListener.handleLogin(mToken, false);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
mListener.handleLogout();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setToken(@Nullable LoginToken token, boolean enteringOnlineMode) {
|
||||||
|
if (token == null)
|
||||||
|
return false;
|
||||||
|
mToken = token;
|
||||||
|
if (enteringOnlineMode) {
|
||||||
|
try {
|
||||||
|
mToken.save(getContext());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mOnlineMode = !enteringOnlineMode;
|
||||||
|
return handleCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void doLogin(String username, String password, NetworkCallback<LoginToken> callback, NetworkErrorCallback error) {
|
||||||
|
startKVVSession(success -> {
|
||||||
|
String kvvJSESSIONID = success.get("JSESSIONID");
|
||||||
|
getSAMLRequest(kvvJSESSIONID, success1 -> startIdentSession(success1.get("Location"), success11 -> {
|
||||||
|
String identJSESSIONID = success11.get("JSESSIONID");
|
||||||
|
String ident_idp_authn_lc_key = success11.get("_idp_authn_lc_key");
|
||||||
|
String identROUTEID = success11.get("ROUTEID");
|
||||||
|
loginIdent(true, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success111 -> loginIdent(false, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success11112 -> {
|
||||||
|
String ident_idp_session = success11112.get("_idp_session");
|
||||||
|
getSAMLResponse(identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, ident_idp_session, success1111 -> loginKVV(success1111.get("RelayState"), success1111.get("SAMLResponse"), kvvJSESSIONID, success111112 -> {
|
||||||
|
LoginToken token = new LoginToken(username, success111112.get("shibsessionKey"), success111112.get("shibsessionName"), kvvJSESSIONID);
|
||||||
|
finishKVVlogin(token, success11111 -> callback.onResponse(token), error);
|
||||||
|
}, error), error);
|
||||||
|
}, error), error);
|
||||||
|
}, error), error);
|
||||||
|
}, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
GET https://kvv.imp.fu-berlin.de/portal/login
|
||||||
|
-> JSESSIONID 5c10406f-588c-4c16-96e9-c80d115417de.tomcat1
|
||||||
|
*/
|
||||||
|
private void startKVVSession(final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
get("https://kvv.imp.fu-berlin.de/portal/login", null, response -> {
|
||||||
|
String cookies = response.getHeaders().get("Set-Cookie");
|
||||||
|
if (cookies==null) {
|
||||||
|
errorCallback.onError(new NetworkError(100101, -1, "Error on starting KVV session!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashMap<String, String> object;
|
||||||
|
try {
|
||||||
|
object = getCookie(cookies, new String[]{"JSESSIONID"});
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
errorCallback.onError(new NetworkError(100102, -1, "Error on starting KVV session!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback.onResponse(object);
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(100100, error.networkResponse.statusCode, "Error on starting KVV session!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
GET https://kvv.imp.fu-berlin.de/sakai-login-tool/container
|
||||||
|
<- JSESSIONID
|
||||||
|
-> (Location-Header) https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
|
||||||
|
?SAMLRequest=fZLLb.....Q8yre3X1IHwkJKE0Mnpy/V9TH4A
|
||||||
|
&RelayState=ss:mem:7ea01e29157b8bd906f7002176.....0d1a505f2c8bf
|
||||||
|
*/
|
||||||
|
private void getSAMLRequest(String JSESSIONID, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
HashMap<String, String> cookies = new HashMap<>();
|
||||||
|
cookies.put("JSESSIONID", JSESSIONID);
|
||||||
|
get("https://kvv.imp.fu-berlin.de/sakai-login-tool/container", cookies, response -> {
|
||||||
|
String location = response.getHeaders().get("Location");
|
||||||
|
if (location==null) {
|
||||||
|
errorCallback.onError(new NetworkError(100111, -1, "Error on getting SAML request!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashMap<String, String> object = new HashMap<>();
|
||||||
|
object.put("Location", location);
|
||||||
|
callback.onResponse(object);
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(100110, error.networkResponse.statusCode, "Error on getting SAML request!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
|
||||||
|
?SAMLRequest=fZLLbsIwEEV/JfI+cWJAUIsgpbAoEi2IpF10UznxUKw6dupxaPn7hkdb2LD29bkzRzNGUeuGZ63fmjV8toA++K61QX58SEnrDLcCFXIjakDuK55njwvOopg3znpbWU2CDBGcV9ZMrcG2BpeD26kKnteLlGy9b5BT+rHbRapuok0bluC0MpEEmm9VWVoNfhshWnpgM7pa5gUJZt0wyogD9h+iJBiv/P6aomQTbtqSdhNtlIYzZg1SOag8zfMlCeazlLyNqpHsy1gO2V1fVsNBMuqJoUyAJaxXDUaiiyG2MDfohfEpYXEyDJM4ZKxgCe/FPI5fSbA6L36vjFTm/bal8hRC/lAUq/C02gs4PK7VBchkfHDNj8Xuwv5trPhVTiY3BeOf4DG96DmVNvypA89nK6tVtQ8yre3X1IHwkJKE0Mnpy/V9TH4A
|
||||||
|
&RelayState=ss:mem:7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
|
||||||
|
-> JSESSIONID C4B6A428BA1F50746235D03F5D107A57
|
||||||
|
-> _idp_authn_lc_key 57a6ae26067f374cc3d0ccfc47e27b04b47752d2a3d4eb2782af0d3994535395
|
||||||
|
-> ROUTEID .1
|
||||||
|
*/
|
||||||
|
private void startIdentSession(String url, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
get(url, null, response -> {
|
||||||
|
String cookies = response.getHeaders().get("Set-Cookie");
|
||||||
|
if (cookies==null) {
|
||||||
|
errorCallback.onError(new NetworkError(100121, -1, "Error on starting Ident session!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashMap<String, String> object;
|
||||||
|
try {
|
||||||
|
object = getCookie(cookies, new String[]{"JSESSIONID", "_idp_authn_lc_key", "ROUTEID"});
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
errorCallback.onError(new NetworkError(100122, -1, "Error on starting Ident session!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback.onResponse(object);
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(100120, error.networkResponse.statusCode, "Error on starting Ident session!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
POST https://identity.fu-berlin.de/idp-fub/Authn/UserPassword
|
||||||
|
<- j_username seedorf96
|
||||||
|
<- j_password neinhieristpatrick
|
||||||
|
<- (Header-"Content-Type") application/x-www-form-urlencoded
|
||||||
|
<- JSESSIONID
|
||||||
|
<- _idp_authn_lc_key
|
||||||
|
<- ROUTEID
|
||||||
|
-> _idp_session OTMuMTkzLjg1LjMz|LQ==|OGYxOWI4MjA2NTQ4YWUwYzJkOWM4Mjk4YzcwZDMwZmJiZjBmMTdmMzkyZGU2OWIwY2JkNmZlNjlmNTRmNzBlMQ==|wLlzQal7VqyntmG2vLNn06wt8wQ=
|
||||||
|
*/
|
||||||
|
private void loginIdent(final boolean first, String username, String password, String JSESSIONID, String _idp_authn_lc_key, String ROUTEID, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
HashMap<String, String> cookies = new HashMap<>();
|
||||||
|
cookies.put("JSESSIONID", JSESSIONID);
|
||||||
|
cookies.put("_idp_authn_lc_key", _idp_authn_lc_key);
|
||||||
|
cookies.put("ROUTEID", ROUTEID);
|
||||||
|
HashMap<String, String> body = new HashMap<>();
|
||||||
|
body.put("j_username", username);
|
||||||
|
body.put("j_password", password);
|
||||||
|
post("https://identity.fu-berlin.de/idp-fub/Authn/UserPassword", cookies, body, response -> {
|
||||||
|
if (first) {
|
||||||
|
callback.onResponse(new HashMap<>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String cookies1 = response.getHeaders().get("Set-Cookie");
|
||||||
|
if (cookies1 ==null) {
|
||||||
|
errorCallback.onError(new NetworkError(100131, -1, "Error on logging in to Identity Server!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashMap<String, String> object;
|
||||||
|
try {
|
||||||
|
object = getCookie(cookies1, new String[]{"_idp_session"});
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
errorCallback.onError(new NetworkError(100132, -1, "Error on logging in to Identity Server!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback.onResponse(object);
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(100130, error.networkResponse.statusCode, "Error on logging in to Identity Server!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
|
||||||
|
<- JSESSIONID
|
||||||
|
<- _idp_authn_lc_key
|
||||||
|
<- ROUTEID
|
||||||
|
<- _idp_session
|
||||||
|
-> (BODY) RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
|
||||||
|
-> (BODY) SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
|
||||||
|
*/
|
||||||
|
private void getSAMLResponse(String JSESSIONID, String _idp_authn_lc_key, String ROUTEID, String _idp_session, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
HashMap<String, String> cookies = new HashMap<>();
|
||||||
|
cookies.put("JSESSIONID", JSESSIONID);
|
||||||
|
cookies.put("_idp_authn_lc_key", _idp_authn_lc_key);
|
||||||
|
cookies.put("ROUTEID", ROUTEID);
|
||||||
|
cookies.put("_idp_session", _idp_session);
|
||||||
|
get("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO", cookies, response -> {
|
||||||
|
String body = response.getParsed();
|
||||||
|
if (body == null) {
|
||||||
|
errorCallback.onError(new NetworkError(100143, -1, "Error on getting SAML response!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<String, String> object = new HashMap<>();
|
||||||
|
|
||||||
|
Pattern pattern = Pattern.compile("ss:mem:([0-9a-f]+)");
|
||||||
|
Matcher matcher = pattern.matcher(body);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
errorCallback.onError(new NetworkError(100142, -1, "Error on getting SAML response!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
object.put("RelayState", "ss:mem:"+matcher.group(1));
|
||||||
|
|
||||||
|
pattern = Pattern.compile("name=\"SAMLResponse\" value=\"([0-9a-zA-Z+]+=*)");
|
||||||
|
matcher = pattern.matcher(body);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
errorCallback.onError(new NetworkError(100141, -1, "Error on getting SAML response!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
object.put("SAMLResponse", matcher.group(1));
|
||||||
|
|
||||||
|
callback.onResponse(object);
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(100140, error.networkResponse.statusCode, "Error on getting SAML response!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
POST https://kvv.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST
|
||||||
|
<- RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
|
||||||
|
<- SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
|
||||||
|
<- JSESSIONID
|
||||||
|
-> _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
|
||||||
|
_b1912c5a03d733a80bd3fee772bf68d4
|
||||||
|
*/
|
||||||
|
private void loginKVV(String RelayState, String SAMLResponse, String JSESSIONID, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
HashMap<String, String> cookies = new HashMap<>();
|
||||||
|
cookies.put("JSESSIONID", JSESSIONID);
|
||||||
|
HashMap<String, String> body = new HashMap<>();
|
||||||
|
body.put("RelayState", RelayState);
|
||||||
|
body.put("SAMLResponse", SAMLResponse);
|
||||||
|
post("https://kvv.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST", cookies, body, response -> {
|
||||||
|
String cookies1 = response.getHeaders().get("Set-Cookie");
|
||||||
|
if (cookies1 ==null) {
|
||||||
|
errorCallback.onError(new NetworkError(100151, -1, "Error on starting KVV session!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashMap<String, String> object = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
Pattern pattern = Pattern.compile("(_shibsession_[0-9a-f]+)=([^;]+);");
|
||||||
|
Matcher matcher = pattern.matcher(cookies1);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
errorCallback.onError(new NetworkError(100152, -1, "Error on starting Ident session!"));
|
||||||
|
}
|
||||||
|
object.put("shibsessionKey", matcher.group(1));
|
||||||
|
object.put("shibsessionName", matcher.group(2));
|
||||||
|
|
||||||
|
callback.onResponse(object);
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(100150, error.networkResponse.statusCode, "Error on starting Ident session!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
GET https://kvv.imp.fu-berlin.de/sakai-login-tool/container
|
||||||
|
<- JSESSIONID
|
||||||
|
<- _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
|
||||||
|
_b1912c5a03d733a80bd3fee772bf68d4
|
||||||
|
*/
|
||||||
|
private void finishKVVlogin(LoginToken loginToken, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
get("https://kvv.imp.fu-berlin.de/sakai-login-tool/container", loginToken.getCookies(), response -> callback.onResponse(new HashMap<>()), error -> errorCallback.onError(new NetworkError(100160, error.networkResponse.statusCode, "Cannot finish login process!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private String getCookie(String cookies, String name) throws NoSuchFieldException {
|
||||||
|
Pattern pattern = Pattern.compile(name+"=([^;]+);");
|
||||||
|
Matcher matcher = pattern.matcher(cookies);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
log.e("GETcookie failed", name);
|
||||||
|
log.e("GETcookie failed", cookies);
|
||||||
|
throw new NoSuchFieldException();
|
||||||
|
}
|
||||||
|
return matcher.group(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashMap<String, String> getCookie(String cookies, String[] names) throws NoSuchFieldException {
|
||||||
|
HashMap<String, String> result = new HashMap<>();
|
||||||
|
for (String name: names) {
|
||||||
|
result.put(name,this.getCookie(cookies, name));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class KVVModules {
|
||||||
|
private final HashMap<String, Object> addons = new HashMap<>();
|
||||||
|
private final KVVLogin login;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public KVVModules(KVVLogin login, Context context) {
|
||||||
|
this.login = login;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public KVVModulesAnnouncements announcements() {
|
||||||
|
return (KVVModulesAnnouncements) addAndGet("announcements", () -> new KVVModulesAnnouncements(login, list(), context));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public KVVModulesList list() {
|
||||||
|
return (KVVModulesList) addAndGet("list", () -> new KVVModulesList(login, context));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Object addAndGet(@NotNull String addon, @NotNull ModuleCreatorInterface creatorInterface) {
|
||||||
|
Object o = addons.get(addon);
|
||||||
|
if (o == null) {
|
||||||
|
o = creatorInterface.create();
|
||||||
|
addons.put(addon, o);
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface ModuleCreatorInterface {
|
||||||
|
@NotNull Object create();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.Spanned;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.services.NewKVV.types.Announcement;
|
||||||
|
import de.sebse.fuplanner.services.NewKVV.types.Modules;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||||
|
|
||||||
|
class KVVModulesAnnouncements extends ModulesPart<ArrayList<Announcement>> {
|
||||||
|
|
||||||
|
KVVModulesAnnouncements(KVVLogin login, KVVModulesList list, Context context) {
|
||||||
|
super(login, list, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ArrayList<Announcement> getPart(Modules.Module module) {
|
||||||
|
return module.announcements;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean setPart(Modules.Module module, ArrayList<Announcement> part) {
|
||||||
|
boolean changed = false;
|
||||||
|
if (module.announcements != null && module.announcements.hashCode() != part.hashCode())
|
||||||
|
changed = true;
|
||||||
|
module.announcements = part;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void upgrade(final String ID, final NetworkCallback<ArrayList<Announcement>> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
if (!login.isInOnlineMode()) {
|
||||||
|
errorCallback.onError(new NetworkError(101204, 500, "Currently running in offline mode!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID), login.getLoginToken().getCookies(), response -> {
|
||||||
|
String body = response.getParsed();
|
||||||
|
if (body == null) {
|
||||||
|
errorCallback.onError(new NetworkError(101201, 403, "No announcements retrieved!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ArrayList<Announcement> announcements = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
JSONObject json = new JSONObject(body);
|
||||||
|
JSONArray sites = json.getJSONArray("announcement_collection");
|
||||||
|
|
||||||
|
for (int i = 0; i < sites.length(); i++) {
|
||||||
|
JSONObject site = sites.getJSONObject(i);
|
||||||
|
String id = site.getString("announcementId");
|
||||||
|
String title = site.getString("title");
|
||||||
|
String text = site.getString("body");
|
||||||
|
text = String.valueOf(fromHtml(text));
|
||||||
|
String createdBy = site.getString("createdByDisplayName");
|
||||||
|
long createdOn = site.getLong("createdOn");
|
||||||
|
|
||||||
|
// Extract attachment links
|
||||||
|
JSONArray attachments = site.getJSONArray("attachments");
|
||||||
|
ArrayList<String> urls = new ArrayList<>();
|
||||||
|
for (int j =0; j<attachments.length(); j++){
|
||||||
|
urls.add(attachments.getJSONObject(j).optString("url",null));
|
||||||
|
}
|
||||||
|
|
||||||
|
announcements.add(new Announcement(id, title, text, createdBy, createdOn, urls));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
errorCallback.onError(new NetworkError(101202, 403, "Cannot parse announcements!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Empty announcements *may be* because token is invalid -> check
|
||||||
|
if (announcements.size() == 0)
|
||||||
|
login.testLoginToken(token -> callback.onResponse(announcements), errorCallback);
|
||||||
|
else
|
||||||
|
callback.onResponse(announcements);
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(101203, error.networkResponse.statusCode, "Cannot get announcements!")));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.regex.MatchResult;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.services.NewKVV.types.Lecturer;
|
||||||
|
import de.sebse.fuplanner.services.NewKVV.types.Modules;
|
||||||
|
import de.sebse.fuplanner.tools.NewAsyncQueue;
|
||||||
|
import de.sebse.fuplanner.tools.Regex;
|
||||||
|
import de.sebse.fuplanner.tools.network.HTTPService;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||||
|
|
||||||
|
import static de.sebse.fuplanner.services.NewKVV.ModulesPart.RETRY_COUNT;
|
||||||
|
|
||||||
|
public class KVVModulesList extends HTTPService {
|
||||||
|
protected final KVVLogin login;
|
||||||
|
@Nullable private Modules modules;
|
||||||
|
private NewAsyncQueue queue = new NewAsyncQueue();
|
||||||
|
|
||||||
|
KVVModulesList(KVVLogin login, Context context) {
|
||||||
|
super(context);
|
||||||
|
this.login = login;
|
||||||
|
restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void find(String moduleID, NetworkCallback<Modules.Module> moduleNetworkCallback, NetworkErrorCallback errorCallback) {
|
||||||
|
find(moduleID, moduleNetworkCallback, errorCallback, RETRY_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void find(String moduleID, NetworkCallback<Modules.Module> moduleNetworkCallback, NetworkErrorCallback errorCallback, int retries) {
|
||||||
|
if (retries < 0) {
|
||||||
|
errorCallback.onError(new NetworkError(101107, -1, "Too many retries!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.modules != null) {
|
||||||
|
Modules.Module module = this.modules.get(moduleID);
|
||||||
|
if (module != null) {
|
||||||
|
moduleNetworkCallback.onResponse(module);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recv(success -> find(moduleID, moduleNetworkCallback, errorCallback, retries - 1), errorCallback, true, RETRY_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void store() {
|
||||||
|
if (this.modules != null) {
|
||||||
|
try {
|
||||||
|
this.modules.save(getContext());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restore() {
|
||||||
|
try {
|
||||||
|
this.modules = Modules.load(getContext());
|
||||||
|
} catch (FileNotFoundException ignored) {
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recv(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
recv(callback, errorCallback, false, RETRY_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recv(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback, boolean forceRefresh, final int retries) {
|
||||||
|
queue.add(() -> {
|
||||||
|
if (this.modules != null && !forceRefresh) {
|
||||||
|
callback.onResponse(this.modules);
|
||||||
|
queue.next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.upgrade(success -> {
|
||||||
|
if (this.modules == null)
|
||||||
|
this.modules = success;
|
||||||
|
else
|
||||||
|
this.modules.updateList(success);
|
||||||
|
callback.onResponse(this.modules);
|
||||||
|
queue.next();
|
||||||
|
}, error -> {
|
||||||
|
if (retries > 0 && (error.getHttpStatus() == 401 || error.getHttpStatus() == 403)) {
|
||||||
|
login.refreshLogin(success -> {
|
||||||
|
recv(callback, errorCallback, forceRefresh, retries-1);
|
||||||
|
queue.next();
|
||||||
|
}, errorCallback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
errorCallback.onError(error);
|
||||||
|
queue.next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void upgrade(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
if (!login.isInOnlineMode()) {
|
||||||
|
errorCallback.onError(new NetworkError(101105, 500, "Currently running in offline mode!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// https://file.io/71sa2V
|
||||||
|
get("https://kvv.imp.fu-berlin.de/direct/site.json", login.getLoginToken().getCookies(), response -> {
|
||||||
|
String body = response.getParsed();
|
||||||
|
if (body == null) {
|
||||||
|
errorCallback.onError(new NetworkError(101101, 403, "No module list retrieved!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Modules modules = new Modules(login.getLoginToken());
|
||||||
|
try {
|
||||||
|
JSONObject json = new JSONObject(body);
|
||||||
|
JSONArray sites = json.getJSONArray("site_collection");
|
||||||
|
|
||||||
|
for (int i = 0; i < sites.length(); i++) {
|
||||||
|
JSONObject site = sites.getJSONObject(i);
|
||||||
|
String semester = site.getJSONObject("props").getString("term_eid");
|
||||||
|
HashSet<String> lvNumbers = new HashSet<>();
|
||||||
|
for (MatchResult matchResult : Regex.allMatches("[0-9]+", site.getJSONObject("props").getString("kvv_lvnumbers"))) {
|
||||||
|
lvNumbers.add(matchResult.group());
|
||||||
|
}
|
||||||
|
String title = site.getString("entityTitle");
|
||||||
|
HashSet<Lecturer> lecturers = new HashSet<>();
|
||||||
|
for (String lecturer : site.getJSONObject("props").getString("kvv_lecturers").split("#")) {
|
||||||
|
if (lecturer.length() > 2)
|
||||||
|
lecturers.add(new Lecturer(lecturer));
|
||||||
|
}
|
||||||
|
String type = site.getJSONObject("props").getString("kvv_coursetype");
|
||||||
|
String description = site.getString("description");
|
||||||
|
description = String.valueOf(ModulesPart.fromHtml(description));
|
||||||
|
String id = site.getString("id");
|
||||||
|
modules.addModule(semester, lvNumbers, title, lecturers, type, description, id);
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
errorCallback.onError(new NetworkError(101102, 403, "Cannot parse module list!"));
|
||||||
|
return;
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
errorCallback.onError(new NetworkError(101103, 403, "Cannot parse module list!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Empty module *may be* because token is invalid -> check
|
||||||
|
if (modules.size() == 0)
|
||||||
|
login.testLoginToken(token -> callback.onResponse(modules), errorCallback);
|
||||||
|
else
|
||||||
|
callback.onResponse(modules);
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(101104, error.networkResponse.statusCode, "Cannot get module list!")));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.Spanned;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.services.NewKVV.types.Modules;
|
||||||
|
import de.sebse.fuplanner.tools.NewAsyncQueue;
|
||||||
|
import de.sebse.fuplanner.tools.network.HTTPService;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||||
|
|
||||||
|
public abstract class ModulesPart<T> extends HTTPService {
|
||||||
|
static final int RETRY_COUNT = 1;
|
||||||
|
protected final KVVLogin login;
|
||||||
|
protected final KVVModulesList list;
|
||||||
|
private NewAsyncQueue queue = new NewAsyncQueue();
|
||||||
|
|
||||||
|
ModulesPart(KVVLogin login, KVVModulesList list, Context context) {
|
||||||
|
super(context);
|
||||||
|
this.login = login;
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recv(final String moduleID, final NetworkCallback<Modules.Module> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
recv(moduleID, callback, errorCallback, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recv(final String moduleID, final NetworkCallback<Modules.Module> callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh) {
|
||||||
|
list.find(moduleID, success -> recv(success, callback, errorCallback, forceRefresh, RETRY_COUNT), errorCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recv(final Modules.Module module, final NetworkCallback<Modules.Module> callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh, final int retries) {
|
||||||
|
queue.add(() -> {
|
||||||
|
if (getPart(module) != null && !forceRefresh) {
|
||||||
|
callback.onResponse(module);
|
||||||
|
queue.next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
upgrade(module.getID(), success -> {
|
||||||
|
if (setPart(module, success)) {
|
||||||
|
this.list.store();
|
||||||
|
}
|
||||||
|
callback.onResponse(module);
|
||||||
|
queue.next();
|
||||||
|
}, error -> {
|
||||||
|
if (retries >= 0 && (error.getHttpStatus() == 401 || error.getHttpStatus() == 403)) {
|
||||||
|
login.refreshLogin(success -> {
|
||||||
|
recv(module, callback, errorCallback, forceRefresh, retries-1);
|
||||||
|
queue.next();
|
||||||
|
}, errorCallback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
errorCallback.onError(error);
|
||||||
|
queue.next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static Spanned fromHtml(String html){
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
|
||||||
|
} else {
|
||||||
|
//noinspection deprecation
|
||||||
|
return Html.fromHtml(html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract T getPart(Modules.Module module);
|
||||||
|
|
||||||
|
protected abstract boolean setPart(Modules.Module module, T part);
|
||||||
|
|
||||||
|
protected abstract void upgrade(final String ID, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback);
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import com.google.android.gms.common.internal.Objects;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Announcement implements Serializable {
|
||||||
|
private final String id;
|
||||||
|
private final String title;
|
||||||
|
private final String body;
|
||||||
|
private final String createdBy;
|
||||||
|
private final long createdOn;
|
||||||
|
private final ArrayList<String> urls;
|
||||||
|
|
||||||
|
public Announcement(String id, String title, String body, String createdBy, long createdOn, ArrayList<String> urls) {
|
||||||
|
|
||||||
|
this.id = id;
|
||||||
|
this.title = title;
|
||||||
|
this.body = body;
|
||||||
|
this.createdBy = createdBy;
|
||||||
|
this.createdOn = createdOn;
|
||||||
|
this.urls = urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<String> getUrls() {
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreatedBy() {
|
||||||
|
return createdBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCreatedOn() {
|
||||||
|
return createdOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ID: "+getId()+
|
||||||
|
"\nTitle: "+getTitle()+
|
||||||
|
"\nBody length: "+getBody().length()+
|
||||||
|
"\nCreated by: "+getCreatedBy()+
|
||||||
|
"\nCreated on: "+getCreatedOn()+
|
||||||
|
"\nURLs: "+getUrls().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(getId(), getBody(), getCreatedBy(), getCreatedOn(), getTitle(), getUrls());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Assignment implements Serializable {
|
||||||
|
private final String id;
|
||||||
|
private final String title;
|
||||||
|
private final long dueTime;
|
||||||
|
private final ArrayList<String> urls;
|
||||||
|
private final String instructions;
|
||||||
|
|
||||||
|
public Assignment(String id, String title, long dueTime, String gradebookItemName, String gradeScale, ArrayList<String> urls, String instructions) {//, String grade
|
||||||
|
this.id = id;
|
||||||
|
this.title = title;
|
||||||
|
this.dueTime = dueTime;
|
||||||
|
this.urls = urls;
|
||||||
|
//this.grade = grade;
|
||||||
|
this.instructions = instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOpen() {
|
||||||
|
return dueTime > System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDueDate() {
|
||||||
|
return dueTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<String> getUrls() {
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInstructions() {
|
||||||
|
return instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ID: "+getId()+
|
||||||
|
"\nTitle: "+getTitle()+
|
||||||
|
"\nDue date: "+getDueDate()+
|
||||||
|
"\nInstructions: "+getInstructions().substring(0, Math.min(getInstructions().length(), 100));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.tools.DateSortedList;
|
||||||
|
|
||||||
|
public class AssignmentList extends DateSortedList<Assignment> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDateByItem(Assignment item) {
|
||||||
|
return item.getDueDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean reversed() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.tools.ColorRGB;
|
||||||
|
|
||||||
|
public class Event implements Serializable {
|
||||||
|
private final String siteId;
|
||||||
|
private final String id;
|
||||||
|
private final String type;
|
||||||
|
private final String title;
|
||||||
|
private final long duration;
|
||||||
|
private final long firstTime;
|
||||||
|
private final String location;
|
||||||
|
|
||||||
|
public Event(String id, String type, String title, long duration, long firstTime, String siteId, String location) {
|
||||||
|
this.siteId = siteId;
|
||||||
|
this.id = id;
|
||||||
|
this.type = type;
|
||||||
|
this.title = title;
|
||||||
|
this.duration = duration;
|
||||||
|
this.firstTime = firstTime;
|
||||||
|
this.location = location
|
||||||
|
.replace(" Übungsraum", "")
|
||||||
|
.replace(" Konferenzraum", "")
|
||||||
|
.replace(" Seminarraum", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return this.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStartDate() {
|
||||||
|
return this.firstTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getEndDate() {
|
||||||
|
return this.firstTime+this.duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModuleId() {
|
||||||
|
return siteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorRGB getColor() {
|
||||||
|
MessageDigest digest;
|
||||||
|
try {
|
||||||
|
digest = MessageDigest.getInstance("SHA-256");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
byte[] encodedHash;
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
|
||||||
|
encodedHash = digest.digest(siteId.getBytes(StandardCharsets.UTF_8));
|
||||||
|
} else {
|
||||||
|
encodedHash = digest.digest(siteId.getBytes());
|
||||||
|
}
|
||||||
|
int h = (0xff & encodedHash[0]) + (0xff & encodedHash[1]) * 255;
|
||||||
|
h = h * 360 / 0xffff;
|
||||||
|
//int s = 0xff & encodedHash[2];
|
||||||
|
//s = s * 100 / 0xffff;
|
||||||
|
//int v = 0xff & encodedHash[3];
|
||||||
|
//v = v * 100 / 0xffff;
|
||||||
|
|
||||||
|
// range for more beautiful colors
|
||||||
|
h = h / 30 * 30;
|
||||||
|
int s = 100;
|
||||||
|
int v = 80;
|
||||||
|
|
||||||
|
return hsvToRgb(h/360.0, s/100.0, v/100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ColorRGB hsvToRgb(double hue, double saturation, double value) {
|
||||||
|
int h = (int)(hue * 6);
|
||||||
|
double f = hue * 6 - h;
|
||||||
|
double p = value * (1 - saturation);
|
||||||
|
double q = value * (1 - f * saturation);
|
||||||
|
double t = value * (1 - (1 - f) * saturation);
|
||||||
|
|
||||||
|
switch (h) {
|
||||||
|
case 0: return new ColorRGB(value, t, p);
|
||||||
|
case 1: return new ColorRGB(q, value, p);
|
||||||
|
case 2: return new ColorRGB(p, value, t);
|
||||||
|
case 3: return new ColorRGB(p, q, value);
|
||||||
|
case 4: return new ColorRGB(t, p, value);
|
||||||
|
case 5: return new ColorRGB(value, p, q);
|
||||||
|
default: throw new RuntimeException("Something went wrong when converting from HSV to RGB. Input was " + hue + ", " + saturation + ", " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ID: "+getId()+
|
||||||
|
"\nType: "+getType()+
|
||||||
|
"\nStart Date: "+getStartDate()+
|
||||||
|
"\nEnd date: "+getEndDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.tools.DateSortedList;
|
||||||
|
|
||||||
|
public class EventList extends DateSortedList<Event> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDateByItem(Event item) {
|
||||||
|
return item.getEndDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean reversed() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class Gradebook implements Serializable {
|
||||||
|
private final String itemName;
|
||||||
|
private final double grade;
|
||||||
|
private final double maxPoints;
|
||||||
|
|
||||||
|
public Gradebook(String itemName, double points, double maxPoints) {
|
||||||
|
this.itemName = itemName;
|
||||||
|
this.grade = points;
|
||||||
|
this.maxPoints = maxPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getMaxPoints() {
|
||||||
|
return maxPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getPoints() {
|
||||||
|
return grade;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getItemName() {
|
||||||
|
return itemName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Name: "+getItemName()+
|
||||||
|
"\nPoints: "+ getPoints()+
|
||||||
|
"\nMax points: "+getMaxPoints();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import de.sebse.fuplanner.tools.logging.Logger;
|
||||||
|
|
||||||
|
public class GroupedEvents {
|
||||||
|
private ArrayList<Group> arrayList = new ArrayList<>();
|
||||||
|
private Logger log = new Logger(this);
|
||||||
|
|
||||||
|
public void add(Event event) {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.setTimeInMillis(event.getStartDate());
|
||||||
|
long dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
|
||||||
|
for (Group group : arrayList) {
|
||||||
|
if (group.add(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arrayList.add(new Group(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Group> getGroups() {
|
||||||
|
return Collections.unmodifiableList(arrayList);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Group {
|
||||||
|
private long firstDate;
|
||||||
|
private long lastDate;
|
||||||
|
private ArrayList<Long> skippedDates;
|
||||||
|
|
||||||
|
private int dayOfWeek;
|
||||||
|
private long startTime;
|
||||||
|
private long duration;
|
||||||
|
|
||||||
|
private Group(Event event) {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.setTimeInMillis(event.getStartDate());
|
||||||
|
dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
|
||||||
|
startTime = calendar.get(Calendar.HOUR_OF_DAY)*3600000+calendar.get(Calendar.MINUTE)*60000+calendar.get(Calendar.SECOND)*1000+calendar.get(Calendar.MILLISECOND);
|
||||||
|
duration = event.getEndDate()-event.getStartDate();
|
||||||
|
|
||||||
|
skippedDates = new ArrayList<>();
|
||||||
|
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
calendar.set(Calendar.MINUTE, 0);
|
||||||
|
calendar.set(Calendar.SECOND, 0);
|
||||||
|
calendar.set(Calendar.MILLISECOND, 0);
|
||||||
|
firstDate = calendar.getTimeInMillis();
|
||||||
|
lastDate = firstDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean add(Event event) {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.setTimeInMillis(event.getStartDate());
|
||||||
|
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
|
||||||
|
int startTime = calendar.get(Calendar.HOUR_OF_DAY)*3600000+calendar.get(Calendar.MINUTE)*60000+calendar.get(Calendar.SECOND)*1000+calendar.get(Calendar.MILLISECOND);
|
||||||
|
long length = event.getEndDate()-event.getStartDate();
|
||||||
|
if (this.dayOfWeek != dayOfWeek || this.startTime != startTime || this.duration != length)
|
||||||
|
return false;
|
||||||
|
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
calendar.set(Calendar.MINUTE, 0);
|
||||||
|
calendar.set(Calendar.SECOND, 0);
|
||||||
|
calendar.set(Calendar.MILLISECOND, 0);
|
||||||
|
long date = calendar.getTimeInMillis();
|
||||||
|
if (date < firstDate) {
|
||||||
|
firstDate = addDays(firstDate, -7);
|
||||||
|
while (firstDate > date) {
|
||||||
|
skippedDates.add(firstDate);
|
||||||
|
firstDate = addDays(firstDate, -7);
|
||||||
|
}
|
||||||
|
} else if (date > lastDate) {
|
||||||
|
lastDate = addDays(lastDate, 7);
|
||||||
|
while (lastDate < date) {
|
||||||
|
skippedDates.add(lastDate);
|
||||||
|
lastDate = addDays(lastDate, 7);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
skippedDates.remove(date);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long addDays(long timeInMillis, int days) {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.setTimeInMillis(timeInMillis);
|
||||||
|
calendar.add(Calendar.DAY_OF_YEAR, days);
|
||||||
|
return calendar.getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getFirstDate() {
|
||||||
|
return firstDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastDate() {
|
||||||
|
return lastDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getSkippedDates() {
|
||||||
|
return Collections.unmodifiableList(skippedDates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDayOfWeek() {
|
||||||
|
return dayOfWeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("%d - %d - %d - %s", dayOfWeek, startTime, duration, skippedDates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class Lecturer implements Serializable {
|
||||||
|
private final String firstName;
|
||||||
|
private final String surname;
|
||||||
|
private final String mail;
|
||||||
|
|
||||||
|
public Lecturer(String parsableString) throws NoSuchFieldException {
|
||||||
|
Pattern pattern = Pattern.compile("([^|]*)\\|([^|]*)\\|([^|]*)\\|\\|", Pattern.DOTALL);
|
||||||
|
Matcher matcher = pattern.matcher(parsableString);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
throw new NoSuchFieldException();
|
||||||
|
}
|
||||||
|
this.firstName = matcher.group(1);
|
||||||
|
this.surname = matcher.group(2);
|
||||||
|
this.mail = matcher.group(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSurname() {
|
||||||
|
return surname;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMail() {
|
||||||
|
return mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "First name: "+ getFirstName()+
|
||||||
|
"\nSurname: "+getSurname()+
|
||||||
|
"\nMail: "+getMail();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by sebastian on 29.10.17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class LoginToken implements Serializable {
|
||||||
|
private static final String FILE_NAME = "LoginTokenSaveFile";
|
||||||
|
|
||||||
|
private final String username;
|
||||||
|
private final String shibsessionKey;
|
||||||
|
private final String shibsessionName;
|
||||||
|
private final String JSESSIONID;
|
||||||
|
@Nullable private String fullName;
|
||||||
|
@Nullable private String email;
|
||||||
|
|
||||||
|
public LoginToken(String username, String shibsessionKey, String shibsessionName, String JSESSIONID) {
|
||||||
|
this.username = username;
|
||||||
|
this.shibsessionKey = shibsessionKey;
|
||||||
|
this.shibsessionName = shibsessionName;
|
||||||
|
this.JSESSIONID = JSESSIONID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static LoginToken load(Context context) throws IOException, ClassNotFoundException {
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = context.openFileInput(FILE_NAME);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ObjectInputStream is = new ObjectInputStream(fis);
|
||||||
|
LoginToken loginToken = (LoginToken) is.readObject();
|
||||||
|
is.close();
|
||||||
|
fis.close();
|
||||||
|
return loginToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(Context context) throws IOException {
|
||||||
|
FileOutputStream fos = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
|
||||||
|
ObjectOutputStream os = new ObjectOutputStream(fos);
|
||||||
|
os.writeObject(this);
|
||||||
|
os.close();
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(Context context) {
|
||||||
|
context.deleteFile(FILE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdditionals(String fullName, String email) {
|
||||||
|
this.fullName = fullName;
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getShibsessionKey() {
|
||||||
|
return shibsessionKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getShibsessionName() {
|
||||||
|
return shibsessionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getJSESSIONID() {
|
||||||
|
return JSESSIONID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullName() {
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, String> getCookies() {
|
||||||
|
HashMap<String, String> cookies = new HashMap<>();
|
||||||
|
cookies.put("JSESSIONID", getJSESSIONID());
|
||||||
|
cookies.put(getShibsessionKey(), getShibsessionName());
|
||||||
|
cookies.put("pasystem_timezone_ok", "true");
|
||||||
|
return cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSameUser(LoginToken token) {
|
||||||
|
return token != null && this.getUsername().equals(token.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
HashMap<String, String> cookies = this.getCookies();
|
||||||
|
for (String header: cookies.keySet()) {
|
||||||
|
result.append(header).append("=").append(cookies.get(header)).append(";");
|
||||||
|
}
|
||||||
|
return result.substring(0, result.length()-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by sebastian on 29.10.17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Modules implements Iterable<Modules.Module>, Serializable {
|
||||||
|
private SortedListModule list;
|
||||||
|
private final LoginToken token;
|
||||||
|
//private transient Logger log = new Logger(this);
|
||||||
|
private static final String FILE_NAME = "ModuleListSaveFile";
|
||||||
|
|
||||||
|
public Modules(LoginToken loginToken) {
|
||||||
|
this.token = loginToken;
|
||||||
|
this.list = new SortedListModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addModule(String semester, HashSet<String> lvNumber, String title, HashSet<Lecturer> lecturer, String type, String description, String ID) {
|
||||||
|
Module m = new Module(semester, lvNumber, title, lecturer, type, description, ID);
|
||||||
|
this.list.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.list.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Iterator<Module> iterator() {
|
||||||
|
return this.list.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Module> latestSemesterIterator() {
|
||||||
|
return this.list.filteredIterator(this.list.getLatestSemester());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return this.list.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Module get(String id) {
|
||||||
|
return this.list.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Module getByIndex(int index) {
|
||||||
|
return this.list.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Modules load(Context context) throws IOException, ClassNotFoundException {
|
||||||
|
FileInputStream fis = context.openFileInput(FILE_NAME);
|
||||||
|
ObjectInputStream is = new ObjectInputStream(fis);
|
||||||
|
Modules modules = (Modules) is.readObject();
|
||||||
|
is.close();
|
||||||
|
fis.close();
|
||||||
|
return modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(Context context) throws IOException {
|
||||||
|
FileOutputStream fos = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
|
||||||
|
ObjectOutputStream os = new ObjectOutputStream(fos);
|
||||||
|
os.writeObject(this);
|
||||||
|
os.close();
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(Context context) {
|
||||||
|
context.deleteFile(FILE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoginToken getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateList(Modules modules) {
|
||||||
|
SortedListModule old = this.list;
|
||||||
|
this.list = modules.list;
|
||||||
|
for (Module oldModule : old) {
|
||||||
|
Module newModule = this.list.getById(oldModule.getID());
|
||||||
|
if (newModule != null) {
|
||||||
|
newModule.announcements = oldModule.announcements;
|
||||||
|
newModule.assignments = oldModule.assignments;
|
||||||
|
newModule.events = oldModule.events;
|
||||||
|
newModule.gradebook = oldModule.gradebook;
|
||||||
|
newModule.resources = oldModule.resources;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Module implements Serializable {
|
||||||
|
public final String semester;
|
||||||
|
final HashSet<String> lvNumber;
|
||||||
|
public final String title;
|
||||||
|
final HashSet<Lecturer> lecturer;
|
||||||
|
public final String type;
|
||||||
|
public final String description;
|
||||||
|
private final String ID;
|
||||||
|
@Nullable public ArrayList<Announcement> announcements;
|
||||||
|
@Nullable public AssignmentList assignments;
|
||||||
|
@Nullable public EventList events;
|
||||||
|
@Nullable public ArrayList<Gradebook> gradebook;
|
||||||
|
@Nullable public ArrayList<Resource> resources;
|
||||||
|
|
||||||
|
/*private Module() {
|
||||||
|
this(null, null, null, null, null);
|
||||||
|
throw new AssertionError("Do not use this constructor!");
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public float getGradebookPercent(){
|
||||||
|
float maxPoint = 0;
|
||||||
|
float userPoint = 0;
|
||||||
|
if (gradebook != null) {
|
||||||
|
for (Gradebook g : gradebook){
|
||||||
|
maxPoint += g.getMaxPoints();
|
||||||
|
userPoint += g.getPoints();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (maxPoint == 0)
|
||||||
|
return 0;
|
||||||
|
return userPoint/maxPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Module(String semester, HashSet<String> lvNumber, String title, HashSet<Lecturer> lecturer, String type, String description, String ID) {
|
||||||
|
semester = semester.replace("SS", "S");
|
||||||
|
semester = semester.replaceAll("[0-9]{2}([0-9]{2})", "$1");
|
||||||
|
title = title.replaceAll("(.*?) (S[0-9]{2}|W[0-9/]{5})", "$1");
|
||||||
|
|
||||||
|
this.semester = semester;
|
||||||
|
this.lvNumber = lvNumber;
|
||||||
|
this.title = title;
|
||||||
|
this.lecturer = lecturer;
|
||||||
|
this.type = type;
|
||||||
|
this.description = description;
|
||||||
|
this.ID = ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getID() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Semester: "+semester+
|
||||||
|
"\nlvNumber: "+lvNumber.toString()+
|
||||||
|
"\ntitle: "+title+
|
||||||
|
"\nlecturer: "+lecturer.toString()+
|
||||||
|
"\ntype: "+type+
|
||||||
|
"\nID: "+ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import androidx.annotation.LayoutRes;
|
||||||
|
import de.sebse.fuplanner.R;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.LayoutItemType;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.TreeNode;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class Resource implements Serializable {
|
||||||
|
|
||||||
|
final String author;
|
||||||
|
final long modifiedDate;
|
||||||
|
final String title;
|
||||||
|
final String url;
|
||||||
|
private final boolean visible;
|
||||||
|
private final String container;
|
||||||
|
|
||||||
|
|
||||||
|
Resource(String author, String title, long modifiedDate, String url, boolean visible, String container) {
|
||||||
|
this.author = author;
|
||||||
|
this.title = title;
|
||||||
|
this.modifiedDate = modifiedDate;
|
||||||
|
this.url = url;
|
||||||
|
this.visible = visible;
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getModifiedDate() {
|
||||||
|
return modifiedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContainer() {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract TreeNode getTreeNode();
|
||||||
|
|
||||||
|
public static class File extends Resource implements LayoutItemType {
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
public File(String author, String title, long modifiedDate, String url, boolean visible, String container, String type) {
|
||||||
|
super(author, title, modifiedDate, url, visible, container);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Resource{" +
|
||||||
|
"author='" + author + '\'' +
|
||||||
|
", modifiedDate=" + modifiedDate +
|
||||||
|
", title='" + title + '\'' +
|
||||||
|
", url='" + url + '\'' +
|
||||||
|
", type='" + type + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TreeNode getTreeNode() {
|
||||||
|
return new TreeNode<>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @LayoutRes int getLayoutId() {
|
||||||
|
return R.layout.item_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Folder extends Resource implements LayoutItemType {
|
||||||
|
|
||||||
|
private final ArrayList<Resource> children;
|
||||||
|
public Folder(String author, String title, long modifiedDate, String url, boolean visible, String container) {
|
||||||
|
super(author, title, modifiedDate, url, visible, container);
|
||||||
|
children = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Resource res){
|
||||||
|
children.add(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource get(int id){
|
||||||
|
return children.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size(){
|
||||||
|
return children.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Resource{" +
|
||||||
|
"author='" + author + '\'' +
|
||||||
|
", modifiedDate=" + modifiedDate +
|
||||||
|
", title='" + title + '\'' +
|
||||||
|
", url='" + url + '\'' +
|
||||||
|
", children='" + children + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TreeNode getTreeNode() {
|
||||||
|
TreeNode dir = new TreeNode<>(this);
|
||||||
|
for (Resource res: children) {
|
||||||
|
dir.addChild(res.getTreeNode());
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @LayoutRes int getLayoutId() {
|
||||||
|
return R.layout.item_dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package de.sebse.fuplanner.services.NewKVV.types;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.tools.Regex;
|
||||||
|
import de.sebse.fuplanner.tools.SortedList;
|
||||||
|
|
||||||
|
public class SortedListModule extends SortedList<Modules.Module, String, String> {
|
||||||
|
private static final int LARGER = 1;
|
||||||
|
private static final int EQUAL = 0;
|
||||||
|
private static final int SMALLER = -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Modules.Module o1, Modules.Module o2) {
|
||||||
|
int semester;
|
||||||
|
try {
|
||||||
|
semester = -compareSemester(o1.semester, o2.semester);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
semester = EQUAL;
|
||||||
|
}
|
||||||
|
if (semester != EQUAL)
|
||||||
|
return semester;
|
||||||
|
return o1.title.compareToIgnoreCase(o2.title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(Modules.Module e) {
|
||||||
|
super.add(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLatestSemester() {
|
||||||
|
if (size() > 0)
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return this.get(0).semester;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int compareSemester(String a, String b) throws NoSuchFieldException {
|
||||||
|
if (a == null && b == null)
|
||||||
|
return EQUAL;
|
||||||
|
if (a == null)
|
||||||
|
return SMALLER;
|
||||||
|
if (b == null)
|
||||||
|
return LARGER;
|
||||||
|
|
||||||
|
String s1type = Regex.regex("^(S|WS) ", a);
|
||||||
|
int s1year = Integer.parseInt(Regex.regex("^(S|WS) ([0-9]{2})", a, 2));
|
||||||
|
String s2type = Regex.regex("^(S|WS) ", b);
|
||||||
|
int s2year = Integer.parseInt(Regex.regex("^(S|WS) ([0-9]{2})", b, 2));
|
||||||
|
|
||||||
|
if (s1year == s2year) {
|
||||||
|
if (s1type.equals(s2type))
|
||||||
|
return EQUAL;
|
||||||
|
return s1type.equals("S") ? SMALLER : LARGER;
|
||||||
|
}
|
||||||
|
return s1year < s2year ? SMALLER : LARGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasIdentifier(Modules.Module o1, String id) {
|
||||||
|
return o1.getID().equals(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasFilter(Modules.Module o1, String filter) {
|
||||||
|
return o1.semester.equals(filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,4 @@ public interface MainActivityListener {
|
|||||||
void addRequestPermissionsResultListener(RequestPermissionsResultListener listener, String id);
|
void addRequestPermissionsResultListener(RequestPermissionsResultListener listener, String id);
|
||||||
|
|
||||||
void removeRequestPermissionsResultListener(String id);
|
void removeRequestPermissionsResultListener(String id);
|
||||||
|
|
||||||
void refreshNavigation();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package de.sebse.fuplanner.tools;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||||
|
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||||
|
|
||||||
|
public class NewAsyncQueue {
|
||||||
|
private final LinkedList<AsyncQueueCallback> mQueue = new LinkedList<>();
|
||||||
|
private boolean mIsRunning = false;
|
||||||
|
|
||||||
|
public void add(AsyncQueueCallback callback) {
|
||||||
|
if (isRunning())
|
||||||
|
getQueue().addLast(callback);
|
||||||
|
else {
|
||||||
|
setRunning(true);
|
||||||
|
callback.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void next() {
|
||||||
|
AsyncQueueCallback callback = getQueue().pollFirst();
|
||||||
|
if (callback == null)
|
||||||
|
setRunning(false);
|
||||||
|
else
|
||||||
|
callback.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface AsyncQueueCallback {
|
||||||
|
void run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkErrorCallback check(NetworkErrorCallback value) {
|
||||||
|
return error -> {
|
||||||
|
value.onError(error);
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> NetworkCallback<T> check(NetworkCallback<T> value) {
|
||||||
|
return success -> {
|
||||||
|
value.onResponse(success);
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRunning() {
|
||||||
|
return mIsRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRunning(boolean value) {
|
||||||
|
mIsRunning = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedList<AsyncQueueCallback> getQueue() {
|
||||||
|
return mQueue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
<include
|
<include
|
||||||
layout="@layout/app_bar_main"
|
layout="@layout/app_bar_main"
|
||||||
|
android:id="@+id/app_bar_include"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<paths>
|
|
||||||
<external-path name="external_files" path="."/>
|
|
||||||
</paths>
|
|
||||||
Reference in New Issue
Block a user