Module Detail Overview Implementation #1
This commit is contained in:
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -25,5 +25,5 @@
|
|||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8 (2)" project-jdk-type="JavaSDK" />
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
|
||||||
</project>
|
</project>
|
||||||
@@ -17,6 +17,12 @@ android {
|
|||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -38,4 +44,6 @@ dependencies {
|
|||||||
implementation 'com.android.support:appcompat-v7:27.1.1'
|
implementation 'com.android.support:appcompat-v7:27.1.1'
|
||||||
implementation 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2'
|
implementation 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2'
|
||||||
implementation 'com.android.support:support-v4:27.1.1'
|
implementation 'com.android.support:support-v4:27.1.1'
|
||||||
|
implementation 'org.jetbrains:annotations-java5:15.0'
|
||||||
|
implementation files('libs/jericho-html-3.4.jar')
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
app/libs/jericho-html-3.4.jar
Normal file
BIN
app/libs/jericho-html-3.4.jar
Normal file
Binary file not shown.
@@ -16,6 +16,8 @@ import android.support.v7.widget.Toolbar;
|
|||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
import de.sebse.fuplanner.fragments.LoginFragment;
|
import de.sebse.fuplanner.fragments.LoginFragment;
|
||||||
import de.sebse.fuplanner.fragments.moddetails.ModDetailFragment;
|
import de.sebse.fuplanner.fragments.moddetails.ModDetailFragment;
|
||||||
import de.sebse.fuplanner.fragments.ModulesFragment;
|
import de.sebse.fuplanner.fragments.ModulesFragment;
|
||||||
@@ -240,21 +242,17 @@ public class MainActivity extends AppCompatActivity
|
|||||||
log.d("Modules.get", success.size());
|
log.d("Modules.get", success.size());
|
||||||
//SubMenu moduleMenu = navigationView.getMenu().findItem(R.id.nav_modules).getSubMenu();
|
//SubMenu moduleMenu = navigationView.getMenu().findItem(R.id.nav_modules).getSubMenu();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Modules.Module module: success) {
|
for (Iterator<Modules.Module> it = success.latestSemesterIterator(); it.hasNext(); ) {
|
||||||
if (module.semester.equals("SS 18")) {
|
Modules.Module module = it.next();
|
||||||
MenuItem menuItem = navigationView.getMenu().add(Menu.NONE, Menu.NONE, 101 + i, module.title);
|
MenuItem menuItem = navigationView.getMenu().add(Menu.NONE, Menu.NONE, 101 + i, module.title);
|
||||||
final int finalI = i;
|
final int finalI = i;
|
||||||
menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
menuItem.setOnMenuItemClickListener(item -> {
|
||||||
@Override
|
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
|
||||||
onModulesFragmentInteraction(finalI);
|
onModulesFragmentInteraction(finalI);
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}, new NetworkErrorCallback() {
|
}, new NetworkErrorCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onError(NetworkError error) {
|
public void onError(NetworkError error) {
|
||||||
|
|||||||
@@ -0,0 +1,165 @@
|
|||||||
|
package de.sebse.fuplanner.fragments.moddetails;
|
||||||
|
|
||||||
|
import android.icu.text.DateFormat;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.R;
|
||||||
|
import de.sebse.fuplanner.fragments.ModulesFragment;
|
||||||
|
import de.sebse.fuplanner.fragments.ModulesRecyclerViewAdapter;
|
||||||
|
import de.sebse.fuplanner.services.KVV.Announcement;
|
||||||
|
import de.sebse.fuplanner.services.KVV.Modules;
|
||||||
|
import de.sebse.fuplanner.tools.Conversion;
|
||||||
|
import de.sebse.fuplanner.tools.ui.CustomViewHolder;
|
||||||
|
|
||||||
|
public class ModDetailOverviewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
private Modules.Module mValue;
|
||||||
|
//private final ModulesFragment.OnModulesFragmentInteractionListener mListener;
|
||||||
|
|
||||||
|
public ModDetailOverviewAdapter(/*ModulesFragment.OnModulesFragmentInteractionListener listener*/) {
|
||||||
|
mValue = null;
|
||||||
|
//mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModule(Modules.Module module) {
|
||||||
|
mValue = module;
|
||||||
|
this.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view;
|
||||||
|
switch (viewType) {
|
||||||
|
case 0:
|
||||||
|
view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.list_all_caption, parent, false);
|
||||||
|
return new HeaderViewHolder(view);
|
||||||
|
case 1:
|
||||||
|
view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.list_moddetails_description, parent, false);
|
||||||
|
return new DescriptionViewHolder(view);
|
||||||
|
case 2:
|
||||||
|
view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.list_moddetails_announcements, parent, false);
|
||||||
|
return new AnnounceViewHolder(view);
|
||||||
|
default:
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
// Just as an example, return 0 or 2 depending on position
|
||||||
|
// Note that unlike in ListView adapters, types don't have to be contiguous
|
||||||
|
if (position < 3)
|
||||||
|
return position % 2;
|
||||||
|
else
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
|
||||||
|
if (mValue == null)
|
||||||
|
return;
|
||||||
|
int announce_count = getAnnounceCount(2);
|
||||||
|
if (position == 0) {
|
||||||
|
HeaderViewHolder h = (HeaderViewHolder) holder;
|
||||||
|
h.mCaption.setText(h.mView.getResources().getText(R.string.description));
|
||||||
|
} else if (position == 1) {
|
||||||
|
DescriptionViewHolder d = (DescriptionViewHolder) holder;
|
||||||
|
d.mText.setText(mValue.description);
|
||||||
|
//d.mText.setText(d.mView.getResources().getText(R.string.app_name));
|
||||||
|
} else if (position == 2) {
|
||||||
|
HeaderViewHolder h = (HeaderViewHolder) holder;
|
||||||
|
h.mCaption.setText(h.mView.getResources().getString(R.string.announcements_count, getAnnounceCount()));
|
||||||
|
} else if (position <= announce_count+2) {
|
||||||
|
AnnounceViewHolder a = (AnnounceViewHolder) holder;
|
||||||
|
Announcement announce = mValue.announcements.get(position - 3);
|
||||||
|
a.mTitle.setText(announce.getTitle());
|
||||||
|
a.mPublisher.setText(announce.getCreatedBy());
|
||||||
|
a.mDate.setText(Conversion.getModifiedDate(announce.getCreatedOn()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
if (mValue != null) {
|
||||||
|
return 3+getAnnounceCount();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getAnnounceCount() {
|
||||||
|
if (mValue.announcements != null)
|
||||||
|
return mValue.announcements.size();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getAnnounceCount(int max) {
|
||||||
|
return Math.min(max, getAnnounceCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class HeaderViewHolder extends CustomViewHolder {
|
||||||
|
final TextView mCaption;
|
||||||
|
|
||||||
|
HeaderViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
mCaption = view.findViewById(R.id.caption);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " '" + mCaption.getText() + "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DescriptionViewHolder extends CustomViewHolder {
|
||||||
|
final TextView mText;
|
||||||
|
|
||||||
|
DescriptionViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
mText = view.findViewById(R.id.description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " '" + mText.getText() + "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class AnnounceViewHolder extends CustomViewHolder {
|
||||||
|
final TextView mTitle;
|
||||||
|
final TextView mPublisher;
|
||||||
|
final TextView mDate;
|
||||||
|
|
||||||
|
AnnounceViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
mTitle = view.findViewById(R.id.title);
|
||||||
|
mPublisher = view.findViewById(R.id.publisher);
|
||||||
|
mDate = view.findViewById(R.id.date);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " '" + mTitle.getText() + "' '" + mPublisher.getText() + "' '" + mDate.getText() + "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
package de.sebse.fuplanner.fragments.moddetails;
|
package de.sebse.fuplanner.fragments.moddetails;
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -11,6 +14,7 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import de.sebse.fuplanner.MainActivity;
|
import de.sebse.fuplanner.MainActivity;
|
||||||
import de.sebse.fuplanner.R;
|
import de.sebse.fuplanner.R;
|
||||||
|
import de.sebse.fuplanner.fragments.ModulesRecyclerViewAdapter;
|
||||||
import de.sebse.fuplanner.services.KVV.KVV;
|
import de.sebse.fuplanner.services.KVV.KVV;
|
||||||
import de.sebse.fuplanner.services.KVV.Modules;
|
import de.sebse.fuplanner.services.KVV.Modules;
|
||||||
import de.sebse.fuplanner.tools.logging.Logger;
|
import de.sebse.fuplanner.tools.logging.Logger;
|
||||||
@@ -69,23 +73,33 @@ public class ModDetailOverviewFragment extends Fragment {
|
|||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
log.d("on create");
|
log.d("on create");
|
||||||
MainActivity activity = (MainActivity) getActivity();
|
|
||||||
View view = inflater.inflate(R.layout.fragment_mod_detail_overview, container, false);
|
View view = inflater.inflate(R.layout.fragment_mod_detail_overview, container, false);
|
||||||
if (activity != null) {
|
// Set the adapter
|
||||||
KVV kvv = activity.getKVV();
|
if (view instanceof RecyclerView) {
|
||||||
/*kvv.getModuleDetails(mItemPos, new NetworkCallback<Modules.UpgradeModule>() {
|
Context context = view.getContext();
|
||||||
@Override
|
RecyclerView recyclerView = (RecyclerView) view;
|
||||||
public void onResponse(@NonNull Modules.UpgradeModule success) {
|
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
final ModDetailOverviewAdapter adapter = new ModDetailOverviewAdapter();
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
|
||||||
|
if (getActivity() != null) {
|
||||||
|
KVV kvv = ((MainActivity) getActivity()).getKVV();
|
||||||
|
kvv.getModuleList((Modules success) -> {
|
||||||
log.d(success);
|
log.d(success);
|
||||||
success.description = "Neue Beschreibung";
|
Modules.Module module = success.get(mItemPos);
|
||||||
|
adapter.setModule(module);
|
||||||
|
kvv.getModuleAnnouncements(module, module1 -> {
|
||||||
|
log.d("announcements", module.announcements);
|
||||||
|
adapter.setModule(module1);
|
||||||
|
}, error -> log.e(error));
|
||||||
|
}, error -> log.e(error));
|
||||||
}
|
}
|
||||||
}, new NetworkErrorCallback() {
|
|
||||||
@Override
|
|
||||||
public void onError(NetworkError error) {
|
|
||||||
log.e(error);
|
|
||||||
}
|
|
||||||
});*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package de.sebse.fuplanner.services.KVV;
|
||||||
|
|
||||||
|
public class Announcement {
|
||||||
|
private final String id;
|
||||||
|
private final String title;
|
||||||
|
private final String body;
|
||||||
|
private final String createdBy;
|
||||||
|
private final long createdOn;
|
||||||
|
|
||||||
|
Announcement(String id, String title, String body, String createdBy, long createdOn) {
|
||||||
|
|
||||||
|
this.id = id;
|
||||||
|
this.title = title;
|
||||||
|
this.body = body;
|
||||||
|
this.createdBy = createdBy;
|
||||||
|
this.createdOn = createdOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,12 +28,9 @@ public class KVV {
|
|||||||
|
|
||||||
public void login(@NonNull String username, @NonNull String password, final NetworkCallback<LoginToken> callback, NetworkErrorCallback error) {
|
public void login(@NonNull String username, @NonNull String password, final NetworkCallback<LoginToken> callback, NetworkErrorCallback error) {
|
||||||
KVVLogin login = new KVVLogin(this.context);
|
KVVLogin login = new KVVLogin(this.context);
|
||||||
login.login(username, password, new NetworkCallback<LoginToken>() {
|
login.login(username, password, success -> {
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull LoginToken success) {
|
|
||||||
lastToken = success;
|
lastToken = success;
|
||||||
callback.onResponse(success);
|
callback.onResponse(success);
|
||||||
}
|
|
||||||
}, error);
|
}, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,32 +40,26 @@ public class KVV {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void getModuleList(final NetworkCallback<Modules> callback, final NetworkErrorCallback error) {
|
public void getModuleList(final NetworkCallback<Modules> callback, final NetworkErrorCallback error) {
|
||||||
this.getLastToken(new LastTokenCallback() {
|
this.getLastToken(token -> {
|
||||||
@Override
|
|
||||||
public void onReceived(LoginToken token) {
|
|
||||||
KVVModuleList modules = (KVVModuleList) addons.get("modules");
|
KVVModuleList modules = (KVVModuleList) addons.get("modules");
|
||||||
if (modules == null) {
|
if (modules == null) {
|
||||||
modules = new KVVModuleList(KVV.this.context, token);
|
modules = new KVVModuleList(KVV.this.context, token);
|
||||||
addons.put("modules", modules);
|
addons.put("modules", modules);
|
||||||
}
|
}
|
||||||
modules.getModuleList(callback, error);
|
modules.getModuleList(callback, error);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public void getModuleDetails(final int index, final NetworkCallback<Modules.UpgradeModule> callback, final NetworkErrorCallback error) {
|
public void getModuleAnnouncements(Modules.Module module, final NetworkCallback<Modules.Module> callback, final NetworkErrorCallback error) {
|
||||||
this.getLastToken(new LastTokenCallback() {
|
this.getLastToken(token -> {
|
||||||
@Override
|
|
||||||
public void onReceived(LoginToken token) {
|
|
||||||
KVVModuleList modules = (KVVModuleList) addons.get("modules");
|
KVVModuleList modules = (KVVModuleList) addons.get("modules");
|
||||||
if (modules == null) {
|
if (modules == null) {
|
||||||
modules = new KVVModuleList(KVV.this.context, token);
|
modules = new KVVModuleList(KVV.this.context, token);
|
||||||
addons.put("modules", modules);
|
addons.put("modules", modules);
|
||||||
}
|
}
|
||||||
modules.getModuleDetails(index, callback, error);
|
modules.getAnnouncements(module, callback, error);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}*/
|
}
|
||||||
|
|
||||||
private void getLastToken(LastTokenCallback lastTokenCallback) {
|
private void getLastToken(LastTokenCallback lastTokenCallback) {
|
||||||
if (this.isUpdating) {
|
if (this.isUpdating) {
|
||||||
|
|||||||
@@ -28,53 +28,23 @@ class KVVLogin extends HTTPService {
|
|||||||
|
|
||||||
public void login(final String username, final String password, final NetworkCallback<LoginToken> callback, final NetworkErrorCallback error) {
|
public void login(final String username, final String password, final NetworkCallback<LoginToken> callback, final NetworkErrorCallback error) {
|
||||||
Log.d("KVVMaster0", username+" - "+password);
|
Log.d("KVVMaster0", username+" - "+password);
|
||||||
startKVVSession(new NetworkCallback<HashMap<String, String>>() {
|
startKVVSession(success -> {
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
|
||||||
final String kvvJSESSIONID = success.get("JSESSIONID");
|
final String kvvJSESSIONID = success.get("JSESSIONID");
|
||||||
getSAMLRequest(kvvJSESSIONID, new NetworkCallback<HashMap<String, String>>() {
|
getSAMLRequest(kvvJSESSIONID, success1 -> startIdentSession(success1.get("Location"), success11 -> {
|
||||||
@Override
|
final String identJSESSIONID = success11.get("JSESSIONID");
|
||||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
final String ident_idp_authn_lc_key = success11.get("_idp_authn_lc_key");
|
||||||
startIdentSession(success.get("Location"), new NetworkCallback<HashMap<String, String>>() {
|
final String identROUTEID = success11.get("ROUTEID");
|
||||||
@Override
|
loginIdent(true, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success111 -> loginIdent(false, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success11112 -> {
|
||||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
final String ident_idp_session = success11112.get("_idp_session");
|
||||||
final String identJSESSIONID = success.get("JSESSIONID");
|
getSAMLResponse(identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, ident_idp_session, success1111 -> loginKVV(success1111.get("RelayState"), success1111.get("SAMLResponse"), kvvJSESSIONID, success111112 -> {
|
||||||
final String ident_idp_authn_lc_key = success.get("_idp_authn_lc_key");
|
final LoginToken token = new LoginToken(username, success111112.get("shibsessionKey"), success111112.get("shibsessionName"), kvvJSESSIONID);
|
||||||
final String identROUTEID = success.get("ROUTEID");
|
finishKVVlogin(token, success11111 -> {
|
||||||
loginIdent(true, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, new NetworkCallback<HashMap<String, String>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
|
||||||
loginIdent(false, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, new NetworkCallback<HashMap<String, String>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
|
||||||
final String ident_idp_session = success.get("_idp_session");
|
|
||||||
getSAMLResponse(identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, ident_idp_session, new NetworkCallback<HashMap<String, String>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
|
||||||
loginKVV(success.get("RelayState"), success.get("SAMLResponse"), kvvJSESSIONID, new NetworkCallback<HashMap<String, String>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
|
||||||
final LoginToken token = new LoginToken(username, success.get("shibsessionKey"), success.get("shibsessionName"), kvvJSESSIONID);
|
|
||||||
finishKVVlogin(token, new NetworkCallback<HashMap<String, String>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull HashMap<String, String> success) {
|
|
||||||
Log.d("KVVMaster", "Login worked!");
|
Log.d("KVVMaster", "Login worked!");
|
||||||
callback.onResponse(token);
|
callback.onResponse(token);
|
||||||
}
|
|
||||||
}, error);
|
}, error);
|
||||||
}
|
}, error), error);
|
||||||
}, error);
|
}, error), error);
|
||||||
}
|
}, error), error);
|
||||||
}, error);
|
|
||||||
}
|
|
||||||
}, error);
|
|
||||||
}
|
|
||||||
}, error);
|
|
||||||
}
|
|
||||||
}, error);
|
|
||||||
}
|
|
||||||
}, error);
|
|
||||||
}
|
|
||||||
}, error);
|
}, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,23 @@
|
|||||||
package de.sebse.fuplanner.services.KVV;
|
package de.sebse.fuplanner.services.KVV;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.android.volley.Response;
|
import net.htmlparser.jericho.Source;
|
||||||
import com.android.volley.VolleyError;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.regex.MatchResult;
|
import java.util.regex.MatchResult;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import de.sebse.fuplanner.tools.AsyncQueue;
|
import de.sebse.fuplanner.tools.AsyncQueue;
|
||||||
|
import de.sebse.fuplanner.tools.Regex;
|
||||||
import de.sebse.fuplanner.tools.network.HTTPService;
|
import de.sebse.fuplanner.tools.network.HTTPService;
|
||||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||||
import de.sebse.fuplanner.tools.network.NetworkError;
|
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||||
import de.sebse.fuplanner.tools.network.Result;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by sebastian on 29.10.17.
|
* Created by sebastian on 29.10.17.
|
||||||
@@ -35,121 +29,13 @@ public class KVVModuleList extends HTTPService {
|
|||||||
//private AsyncQueue<NetworkCallback<String>, NetworkErrorCallback> queueUpgradeModule = new AsyncQueue<>();
|
//private AsyncQueue<NetworkCallback<String>, NetworkErrorCallback> queueUpgradeModule = new AsyncQueue<>();
|
||||||
private AsyncQueue queueModuleDetails = new AsyncQueue();
|
private AsyncQueue queueModuleDetails = new AsyncQueue();
|
||||||
|
|
||||||
public KVVModuleList(Context context, LoginToken token) {
|
KVVModuleList(Context context, LoginToken token) {
|
||||||
super(context);
|
super(context);
|
||||||
this.token = token;
|
this.token = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public void getModuleList(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
|
|
||||||
if (moduleList != null) {
|
|
||||||
callback.onResponse(moduleList);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
get("https://kvv.imp.fu-berlin.de/portal/site/~" + token.getUsername(), token.getCookies(), new Response.Listener<Result>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Result response) {
|
|
||||||
// tool/([0-9a-f-]*)"(.|\n|\r){0,200}icon-sakai--fu-berlin-joinablecoursebrowser
|
|
||||||
String body = response.getParsed();
|
|
||||||
log.d("FIRST STEP", body);
|
|
||||||
log.d("FIRST STEP", response.getHeaders().get("Location"));
|
|
||||||
final String id;
|
|
||||||
try {
|
|
||||||
//language=RegExp
|
|
||||||
id = regex("tool/([0-9a-f-]*)\"(.|\\n|\\r){0,200}icon-sakai--fu-berlin-joinablecoursebrowser", body);
|
|
||||||
} catch (NoSuchFieldException e) {
|
|
||||||
errorCallback.onError(new NetworkError(101105, -1, "Cannot parse module list!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
get("https://kvv.imp.fu-berlin.de/portal/site/~" + token.getUsername() + "/tool/9df8c796-7d6b-4416-8ba1-f505ea6b8224/", token.getCookies(), new Response.Listener<Result>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Result response) {
|
|
||||||
String location = response.getHeaders().get("Location");
|
|
||||||
get("https://kvv.imp.fu-berlin.de/portal/site/~"+token.getUsername()+"/tool/9df8c796-7d6b-4416-8ba1-f505ea6b8224/"+location, token.getCookies(), new Response.Listener<Result>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Result response) {
|
|
||||||
String body = response.getParsed();
|
|
||||||
//largeLog("KVVModules", body);
|
|
||||||
Pattern pattern = Pattern.compile("<tbody>(.*)</tbody>", Pattern.DOTALL);
|
|
||||||
Matcher matcher = pattern.matcher(body);
|
|
||||||
if (!matcher.find()) {
|
|
||||||
errorCallback.onError(new NetworkError(101104, -1, "Cannot parse module list!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//largeLog("KVVGroup", matcher.group(1));
|
|
||||||
Modules modules = new Modules();
|
|
||||||
//<tr.*?>(.|\n)+?</tr>
|
|
||||||
for (MatchResult match: allMatches(Pattern.compile("<tr.*?>.+?</tr>", Pattern.DOTALL), matcher.group(1))) {
|
|
||||||
try {
|
|
||||||
// Instructors
|
|
||||||
HashSet<String> instructs = new HashSet<>();
|
|
||||||
String instructors = regex("<td class=\"instructors\">.+?<div>(.+?)</div>.+?</td>", match.group());
|
|
||||||
for (MatchResult match2: allMatches(Pattern.compile(".*(?=,)"), instructors)) {
|
|
||||||
if (match2.group()!=null && match2.group().length()>0)
|
|
||||||
instructs.add(match2.group());
|
|
||||||
}
|
|
||||||
for (MatchResult match2: allMatches(Pattern.compile(".*(?=\\s+$|$)"), instructors)) {
|
|
||||||
if (match2.group()!=null && match2.group().length()>0)
|
|
||||||
instructs.add(match2.group());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Semester
|
|
||||||
String semester = regex("<div>((Winter|Sommer)semester.*?)</div>", match.group());
|
|
||||||
|
|
||||||
// lvNumber
|
|
||||||
HashSet<String> lvNumbers = new HashSet<>();
|
|
||||||
String numbers = regex("<td class=\"vvid\">.*?<div>(.*?)</div", match.group());
|
|
||||||
for (MatchResult match2: allMatches(Pattern.compile("\\d+"), numbers)) {
|
|
||||||
if (match2.group()!=null && match2.group().length()>0)
|
|
||||||
lvNumbers.add(match2.group());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Title
|
|
||||||
//language=RegExp
|
|
||||||
String title = regex("<span class=\"fs\"></span>(.+?)</a><span>", match.group());
|
|
||||||
|
|
||||||
// Type
|
|
||||||
//language=RegExp
|
|
||||||
String type = regex("<td class=\"typelong\">.*?<div>(.*?)</div>", match.group());
|
|
||||||
|
|
||||||
// Upgrade URI
|
|
||||||
//language=RegExp
|
|
||||||
String upgradeURI = regex("<a href=\"\\./\\?([0-9]*-[0-9]*\\.ILinkListener-tableform-coursetable-body-rows-[0-9]*-cells-[0-9]*-cell-thelink)\"><span class=\"fs\"></span>.+?</a><span>", match.group());
|
|
||||||
|
|
||||||
modules.addModule(semester, lvNumbers, title, instructs, type, upgradeURI);
|
|
||||||
} catch (NoSuchFieldException e) {
|
|
||||||
errorCallback.onError(new NetworkError(101102, -1, "Cannot parse module list!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
KVVModuleList.this.moduleList = modules;
|
|
||||||
callback.onResponse(modules);
|
|
||||||
}
|
|
||||||
}, new Response.ErrorListener() {
|
|
||||||
@Override
|
|
||||||
public void onErrorResponse(VolleyError error) {
|
|
||||||
errorCallback.onError(new NetworkError(101101, error.networkResponse.statusCode, "Cannot get module list!"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, new Response.ErrorListener() {
|
|
||||||
@Override
|
|
||||||
public void onErrorResponse(VolleyError error) {
|
|
||||||
errorCallback.onError(new NetworkError(101100, error.networkResponse.statusCode, "Cannot get module list!"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, new Response.ErrorListener() {
|
|
||||||
@Override
|
|
||||||
public void onErrorResponse(VolleyError error) {
|
|
||||||
errorCallback.onError(new NetworkError(101103, error.networkResponse.statusCode, "Cannot get module list!"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public void getModuleList(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
|
public void getModuleList(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
|
||||||
get("https://kvv.imp.fu-berlin.de/direct/site.json", token.getCookies(), new Response.Listener<Result>() {
|
get("https://kvv.imp.fu-berlin.de/direct/site.json", token.getCookies(), response -> {
|
||||||
@Override
|
|
||||||
public void onResponse(Result response) {
|
|
||||||
String body = response.getParsed();
|
String body = response.getParsed();
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
errorCallback.onError(new NetworkError(101101, 403, "No module list retreived!"));
|
errorCallback.onError(new NetworkError(101101, 403, "No module list retreived!"));
|
||||||
@@ -164,7 +50,7 @@ public class KVVModuleList extends HTTPService {
|
|||||||
JSONObject site = sites.getJSONObject(i);
|
JSONObject site = sites.getJSONObject(i);
|
||||||
String semester = site.getJSONObject("props").getString("term_eid");
|
String semester = site.getJSONObject("props").getString("term_eid");
|
||||||
HashSet<String> lvNumbers = new HashSet<>();
|
HashSet<String> lvNumbers = new HashSet<>();
|
||||||
for (MatchResult matchResult : allMatches(Pattern.compile("[0-9]+"), site.getJSONObject("props").getString("kvv_lvnumbers"))) {
|
for (MatchResult matchResult : Regex.allMatches("[0-9]+", site.getJSONObject("props").getString("kvv_lvnumbers"))) {
|
||||||
lvNumbers.add(matchResult.group());
|
lvNumbers.add(matchResult.group());
|
||||||
}
|
}
|
||||||
String title = site.getString("entityTitle");
|
String title = site.getString("entityTitle");
|
||||||
@@ -174,8 +60,10 @@ public class KVVModuleList extends HTTPService {
|
|||||||
lecturers.add(new Lecturer(lecturer));
|
lecturers.add(new Lecturer(lecturer));
|
||||||
}
|
}
|
||||||
String type = site.getJSONObject("props").getString("kvv_coursetype");
|
String type = site.getJSONObject("props").getString("kvv_coursetype");
|
||||||
|
String description = site.getString("description");
|
||||||
|
description = new Source(description).getRenderer().toString();
|
||||||
String id = site.getString("id");
|
String id = site.getString("id");
|
||||||
modules.addModule(semester, lvNumbers, title, lecturers, type, id);
|
modules.addModule(semester, lvNumbers, title, lecturers, type, description, id);
|
||||||
}
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
errorCallback.onError(new NetworkError(101102, 403, "Cannot parse module list!"));
|
errorCallback.onError(new NetworkError(101102, 403, "Cannot parse module list!"));
|
||||||
@@ -186,104 +74,59 @@ public class KVVModuleList extends HTTPService {
|
|||||||
}
|
}
|
||||||
moduleList = modules;
|
moduleList = modules;
|
||||||
callback.onResponse(moduleList);
|
callback.onResponse(moduleList);
|
||||||
|
}, error -> errorCallback.onError(new NetworkError(101104, error.networkResponse.statusCode, "Cannot get module list!")));
|
||||||
}
|
}
|
||||||
}, new Response.ErrorListener() {
|
|
||||||
@Override
|
public void getModule(int index, final NetworkCallback<Modules.Module> callback, final NetworkErrorCallback errorCallback) {
|
||||||
public void onErrorResponse(VolleyError error) {
|
this.getModuleList(success -> {
|
||||||
errorCallback.onError(new NetworkError(101103, error.networkResponse.statusCode, "Cannot get module list!"));
|
callback.onResponse(success.get(index));
|
||||||
|
}, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void getAnnouncements(Modules.Module module, final NetworkCallback<Modules.Module> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
queueModuleDetails.add(module.getID(), () -> {
|
||||||
|
if (module.announcements != null) {
|
||||||
|
callback.onResponse(module);
|
||||||
|
queueModuleDetails.next(module.getID());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getAnnouncementsUpgrade(module.getID(), success -> {
|
||||||
|
module.announcements = success;
|
||||||
|
callback.onResponse(module);
|
||||||
|
queueModuleDetails.next(module.getID());
|
||||||
|
}, errorCallback);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void getAnnouncementsUpgrade(String ID, final NetworkCallback<ArrayList<Announcement>> callback, final NetworkErrorCallback errorCallback) {
|
||||||
|
log.d("SITE GET URL", String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID));
|
||||||
/*public void getModuleDetails(final int index, final NetworkCallback<Modules.UpgradeModule> callback, final NetworkErrorCallback errorCallback) {
|
get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID), token.getCookies(), response -> {
|
||||||
queueModuleDetails.add(new AsyncQueue.AsyncQueueCallback() {
|
String body = response.getParsed();
|
||||||
@Override
|
if (body == null) {
|
||||||
public void run() {
|
errorCallback.onError(new NetworkError(101201, 403, "No announcements retreived!"));
|
||||||
if (moduleList == null) {
|
|
||||||
KVVModuleList.this.getModuleList(new NetworkCallback<Modules>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull Modules success) {
|
|
||||||
getModuleDetails(index, callback, errorCallback);
|
|
||||||
queueModuleDetails.next();
|
|
||||||
}
|
|
||||||
}, queueModuleDetails.check(errorCallback));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Modules.Module m = moduleList.get(index);
|
ArrayList<Announcement> announcements = new ArrayList<>();
|
||||||
if (m instanceof Modules.UpgradeModule) {
|
try {
|
||||||
callback.onResponse((Modules.UpgradeModule) m);
|
JSONObject json = new JSONObject(body);
|
||||||
queueModuleDetails.next();
|
JSONArray sites = json.getJSONArray("announcement_collection");
|
||||||
|
|
||||||
|
for (int i = 0; i < sites.length(); i++) {
|
||||||
|
log.d("ANNOUNCEMENT FOUND!", i);
|
||||||
|
JSONObject site = sites.getJSONObject(i);
|
||||||
|
String id = site.getString("announcementId");
|
||||||
|
String title = site.getString("title");
|
||||||
|
String text = site.getString("body");
|
||||||
|
text = new Source(text).getRenderer().toString();
|
||||||
|
String createdBy = site.getString("createdByDisplayName");
|
||||||
|
long createdOn = site.getLong("createdOn");
|
||||||
|
announcements.add(new Announcement(id, title, text, createdBy, createdOn));
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
errorCallback.onError(new NetworkError(101202, 403, "Cannot parse announcements!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
upgradeModule((Modules.SimpleModule) m, new NetworkCallback<String>() {
|
callback.onResponse(announcements);
|
||||||
@Override
|
}, error -> errorCallback.onError(new NetworkError(101203, error.networkResponse.statusCode, "Cannot get announcements!")));
|
||||||
public void onResponse(@NonNull String success) {
|
|
||||||
callback.onResponse(moduleList.upgradeItem(index, success));
|
|
||||||
queueModuleDetails.next();
|
|
||||||
}
|
|
||||||
}, queueModuleDetails.check(errorCallback));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void upgradeModule(Modules.SimpleModule module, final NetworkCallback<String> callback, final NetworkErrorCallback errorCallback) {
|
|
||||||
callback.onResponse("cool ID");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private String regex(String regex, String match) throws NoSuchFieldException {
|
|
||||||
return regex(regex, match, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String regex(String regex, String match, int group) throws NoSuchFieldException {
|
|
||||||
Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
|
|
||||||
Matcher matcher = pattern.matcher(match);
|
|
||||||
if (!matcher.find()) {
|
|
||||||
throw new NoSuchFieldException();
|
|
||||||
}
|
|
||||||
return matcher.group(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Iterable<MatchResult> allMatches(final Pattern p, final CharSequence input) {
|
|
||||||
return new Iterable<MatchResult>() {
|
|
||||||
@NonNull
|
|
||||||
public Iterator<MatchResult> iterator() {
|
|
||||||
return new Iterator<MatchResult>() {
|
|
||||||
// Use a matcher internally.
|
|
||||||
final Matcher matcher = p.matcher(input);
|
|
||||||
// Keep a match around that supports any interleaving of hasNext/next calls.
|
|
||||||
MatchResult pending;
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
// Lazily fill pending, and avoid calling find() multiple times if the
|
|
||||||
// clients call hasNext() repeatedly before sampling via next().
|
|
||||||
if (pending == null && matcher.find()) {
|
|
||||||
pending = matcher.toMatchResult();
|
|
||||||
}
|
|
||||||
return pending != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MatchResult next() {
|
|
||||||
// Fill pending if necessary (as when clients call next() without
|
|
||||||
// checking hasNext()), throw if not possible.
|
|
||||||
if (!hasNext()) { throw new NoSuchElementException(); }
|
|
||||||
// Consume pending so next call to hasNext() does a find().
|
|
||||||
MatchResult next = pending;
|
|
||||||
pending = null;
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Required to satisfy the interface, but unsupported. */
|
|
||||||
public void remove() { throw new UnsupportedOperationException(); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class Lecturer {
|
|||||||
private final String surname;
|
private final String surname;
|
||||||
private final String mail;
|
private final String mail;
|
||||||
|
|
||||||
public Lecturer(String parsableString) throws NoSuchFieldException {
|
Lecturer(String parsableString) throws NoSuchFieldException {
|
||||||
Pattern pattern = Pattern.compile("([^|]*)\\|([^|]*)\\|([^|]*)\\|\\|", Pattern.DOTALL);
|
Pattern pattern = Pattern.compile("([^|]*)\\|([^|]*)\\|([^|]*)\\|\\|", Pattern.DOTALL);
|
||||||
Matcher matcher = pattern.matcher(parsableString);
|
Matcher matcher = pattern.matcher(parsableString);
|
||||||
if (!matcher.find()) {
|
if (!matcher.find()) {
|
||||||
|
|||||||
@@ -1,31 +1,105 @@
|
|||||||
package de.sebse.fuplanner.services.KVV;
|
package de.sebse.fuplanner.services.KVV;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v7.util.SortedList;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import de.sebse.fuplanner.tools.EventEmitter;
|
import de.sebse.fuplanner.tools.Compare;
|
||||||
import de.sebse.fuplanner.tools.Triplet;
|
import de.sebse.fuplanner.tools.Regex;
|
||||||
|
import de.sebse.fuplanner.tools.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by sebastian on 29.10.17.
|
* Created by sebastian on 29.10.17.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Modules /*extends EventEmitter<Triplet<Integer, Modules.UpgradeModule, ArrayList<String>>>*/ implements Iterable<Modules.Module> {
|
public class Modules /*extends EventEmitter<Triplet<Integer, Modules.UpgradeModule, ArrayList<String>>>*/ implements Iterable<Modules.Module> {
|
||||||
private final ArrayList<Module> list;
|
private final SortedList<Module> list;
|
||||||
|
private String latestSemester = null;
|
||||||
|
private Logger log = new Logger(this);
|
||||||
|
|
||||||
Modules() {
|
Modules() {
|
||||||
this.list = new ArrayList<>();
|
this.list = new SortedList<>(Module.class, new SortedList.Callback<Module>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Module o1, Module o2) {
|
||||||
|
return o1.semester.compareTo(o2.semester);
|
||||||
}
|
}
|
||||||
|
|
||||||
Module addModule(String semester, HashSet<String> lvNumber, String title, HashSet<Lecturer> lecturer, String type, String ID) {
|
@Override
|
||||||
Module m = new Module(semester, lvNumber, title, lecturer, type, ID);
|
public void onChanged(int position, int count) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(Module oldItem, Module newItem) {
|
||||||
|
return compare(oldItem, newItem) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(Module item1, Module item2) {
|
||||||
|
return item1.ID.equals(item2.ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInserted(int position, int count) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRemoved(int position, int count) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMoved(int fromPosition, int toPosition) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Module 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);
|
this.list.add(m);
|
||||||
|
try {
|
||||||
|
setLatestSemester(m.semester);
|
||||||
|
} catch (NoSuchFieldException ignored) {
|
||||||
|
}
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setLatestSemester(String semester) throws NoSuchFieldException {
|
||||||
|
if (compareSemester(this.latestSemester, semester) == Compare.LARGER)
|
||||||
|
this.latestSemester = semester;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Compare compareSemester(String a, String b) throws NoSuchFieldException {
|
||||||
|
if (a == null && b == null)
|
||||||
|
return Compare.EQUAL;
|
||||||
|
if (a == null)
|
||||||
|
return Compare.LARGER;
|
||||||
|
if (b == null)
|
||||||
|
return Compare.SMALLER;
|
||||||
|
|
||||||
|
String s1type = Regex.regex("(SS|WS)", a);
|
||||||
|
int s1year = Integer.parseInt(Regex.regex("(SS|WS) ([0-9]{2})", a, 2));
|
||||||
|
String s2type = Regex.regex("(SS|WS)", b);
|
||||||
|
int s2year = Integer.parseInt(Regex.regex("(SS|WS) ([0-9]{2})", b, 2));
|
||||||
|
|
||||||
|
if (s1year == s2year) {
|
||||||
|
if (s1type.equals(s2type))
|
||||||
|
return Compare.EQUAL;
|
||||||
|
if (s1type.equals("SS"))
|
||||||
|
return Compare.SMALLER;
|
||||||
|
return Compare.LARGER;
|
||||||
|
}
|
||||||
|
if (s1year < s2year)
|
||||||
|
return Compare.LARGER;
|
||||||
|
return Compare.SMALLER;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.list.toString();
|
return this.list.toString();
|
||||||
@@ -35,15 +109,18 @@ public class Modules /*extends EventEmitter<Triplet<Integer, Modules.UpgradeModu
|
|||||||
@Override
|
@Override
|
||||||
public Iterator<Module> iterator() {
|
public Iterator<Module> iterator() {
|
||||||
return new Iterator<Module>() {
|
return new Iterator<Module>() {
|
||||||
private final Iterator<Module> iter = Modules.this.list.iterator();
|
private int pos = -1;
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return iter.hasNext();
|
return pos+1 < list.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Module next() {
|
public Module next() {
|
||||||
return iter.next();
|
pos++;
|
||||||
|
if (pos < list.size())
|
||||||
|
return list.get(pos);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -53,6 +130,47 @@ public class Modules /*extends EventEmitter<Triplet<Integer, Modules.UpgradeModu
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Iterator<Module> latestSemesterIterator() {
|
||||||
|
return new Iterator<Module>() {
|
||||||
|
private int index = -1;
|
||||||
|
private int next = -1;
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
if (index==next)
|
||||||
|
predict();
|
||||||
|
return next != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Module next() {
|
||||||
|
if (index == next)
|
||||||
|
predict();
|
||||||
|
if (next == -1)
|
||||||
|
return null;
|
||||||
|
index = next;
|
||||||
|
return list.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException("no changes allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void predict() {
|
||||||
|
int size = list.size();
|
||||||
|
do {
|
||||||
|
next++;
|
||||||
|
} while (next < size && !accept(list.get(next)));
|
||||||
|
if (next == size)
|
||||||
|
next = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean accept(Module ob){
|
||||||
|
return ob.semester.equals(latestSemester);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
return this.list.size();
|
return this.list.size();
|
||||||
}
|
}
|
||||||
@@ -67,14 +185,16 @@ public class Modules /*extends EventEmitter<Triplet<Integer, Modules.UpgradeModu
|
|||||||
public final String title;
|
public final String title;
|
||||||
public final HashSet<Lecturer> lecturer;
|
public final HashSet<Lecturer> lecturer;
|
||||||
public final String type;
|
public final String type;
|
||||||
|
public final String description;
|
||||||
private final String ID;
|
private final String ID;
|
||||||
|
public ArrayList<Announcement> announcements;
|
||||||
|
|
||||||
/*private Module() {
|
/*private Module() {
|
||||||
this(null, null, null, null, null);
|
this(null, null, null, null, null);
|
||||||
throw new AssertionError("Do not use this constructor!");
|
throw new AssertionError("Do not use this constructor!");
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
private Module(String semester, HashSet<String> lvNumber, String title, HashSet<Lecturer> lecturer, String type, String ID) {
|
private Module(String semester, HashSet<String> lvNumber, String title, HashSet<Lecturer> lecturer, String type, String description, String ID) {
|
||||||
semester = semester.replace("Sommersemester", "SS").replace("Wintersemester", "WS");
|
semester = semester.replace("Sommersemester", "SS").replace("Wintersemester", "WS");
|
||||||
semester = semester.replaceAll("[0-9]{2}([0-9]{2})", "$1");
|
semester = semester.replaceAll("[0-9]{2}([0-9]{2})", "$1");
|
||||||
|
|
||||||
@@ -83,9 +203,14 @@ public class Modules /*extends EventEmitter<Triplet<Integer, Modules.UpgradeModu
|
|||||||
this.title = title;
|
this.title = title;
|
||||||
this.lecturer = lecturer;
|
this.lecturer = lecturer;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.description = description;
|
||||||
this.ID = ID;
|
this.ID = ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getID() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Semester: "+semester+
|
return "Semester: "+semester+
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package de.sebse.fuplanner.tools;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||||
@@ -9,22 +10,22 @@ import de.sebse.fuplanner.tools.network.NetworkError;
|
|||||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||||
|
|
||||||
public class AsyncQueue {
|
public class AsyncQueue {
|
||||||
private LinkedList<AsyncQueueCallback> mQueue = new LinkedList<>();
|
private HashMap<String, LinkedList<AsyncQueueCallback>> mQueues = new HashMap<>();
|
||||||
private boolean mRunning = false;
|
private HashMap<String, Boolean> mRunnings = new HashMap<>();
|
||||||
|
|
||||||
public void add(AsyncQueueCallback callback) {
|
public void add(String hash, AsyncQueueCallback callback) {
|
||||||
if (mRunning)
|
if (isRunning(hash))
|
||||||
mQueue.addLast(callback);
|
getQueue(hash).addLast(callback);
|
||||||
else {
|
else {
|
||||||
mRunning = true;
|
setRunning(hash, true);
|
||||||
callback.run();
|
callback.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next() {
|
public void next(String hash) {
|
||||||
AsyncQueueCallback callback = mQueue.pollFirst();
|
AsyncQueueCallback callback = getQueue(hash).pollFirst();
|
||||||
if (callback == null)
|
if (callback == null)
|
||||||
mRunning = false;
|
setRunning(hash, false);
|
||||||
else
|
else
|
||||||
callback.run();
|
callback.run();
|
||||||
}
|
}
|
||||||
@@ -33,25 +34,33 @@ public class AsyncQueue {
|
|||||||
void run();
|
void run();
|
||||||
}
|
}
|
||||||
|
|
||||||
public NetworkErrorCallback check(final NetworkErrorCallback value) {
|
public NetworkErrorCallback check(String hash, NetworkErrorCallback value) {
|
||||||
return new NetworkErrorCallback() {
|
return error -> {
|
||||||
@Override
|
|
||||||
public void onError(NetworkError error) {
|
|
||||||
value.onError(error);
|
value.onError(error);
|
||||||
next();
|
next(hash);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> NetworkCallback<T> check(final NetworkCallback<T> value) {
|
public <T> NetworkCallback<T> check(String hash, NetworkCallback<T> value) {
|
||||||
return new NetworkCallback<T>() {
|
return success -> {
|
||||||
@Override
|
|
||||||
public void onResponse(@NonNull T success) {
|
|
||||||
value.onResponse(success);
|
value.onResponse(success);
|
||||||
next();
|
next(hash);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isRunning(String hash) {
|
||||||
|
return mRunnings.containsKey(hash) && mRunnings.get(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRunning(String hash, boolean value) {
|
||||||
|
mRunnings.put(hash, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedList<AsyncQueueCallback> getQueue(String hash) {
|
||||||
|
if (mQueues.get(hash) == null)
|
||||||
|
mQueues.put(hash, new LinkedList<>());
|
||||||
|
return mQueues.get(hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*public class AsyncQueue<T, U> {
|
/*public class AsyncQueue<T, U> {
|
||||||
|
|||||||
7
app/src/main/java/de/sebse/fuplanner/tools/Compare.java
Normal file
7
app/src/main/java/de/sebse/fuplanner/tools/Compare.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package de.sebse.fuplanner.tools;
|
||||||
|
|
||||||
|
public enum Compare {
|
||||||
|
SMALLER,
|
||||||
|
EQUAL,
|
||||||
|
LARGER
|
||||||
|
}
|
||||||
35
app/src/main/java/de/sebse/fuplanner/tools/Conversion.java
Normal file
35
app/src/main/java/de/sebse/fuplanner/tools/Conversion.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package de.sebse.fuplanner.tools;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.text.format.DateFormat;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class Conversion {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static String getModifiedDate(long modified) {
|
||||||
|
return getModifiedDate(Locale.getDefault(), modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getModifiedDate(Locale locale, long modified) {
|
||||||
|
SimpleDateFormat dateFormat = null;
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||||
|
dateFormat = new SimpleDateFormat(getDateFormat(locale));
|
||||||
|
} else {
|
||||||
|
dateFormat = new SimpleDateFormat("MMM/dd/yyyy hh:mm:ss aa");
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateFormat.format(new Date(modified));
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||||
|
public static String getDateFormat(Locale locale) {
|
||||||
|
return DateFormat.getBestDateTimePattern(locale, "MM/dd/yyyy hh:mm:ss aa");
|
||||||
|
}
|
||||||
|
}
|
||||||
63
app/src/main/java/de/sebse/fuplanner/tools/Regex.java
Normal file
63
app/src/main/java/de/sebse/fuplanner/tools/Regex.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package de.sebse.fuplanner.tools;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.intellij.lang.annotations.Language;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.regex.MatchResult;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class Regex {
|
||||||
|
public static String regex(@Language("Regexp") String regex, String match) throws NoSuchFieldException {
|
||||||
|
return regex(regex, match, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String regex(@Language("Regexp") String regex, String match, int group) throws NoSuchFieldException {
|
||||||
|
Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
|
||||||
|
Matcher matcher = pattern.matcher(match);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
throw new NoSuchFieldException();
|
||||||
|
}
|
||||||
|
return matcher.group(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Iterable<MatchResult> allMatches(@Language("Regexp") String regex, final CharSequence input) {
|
||||||
|
final Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
|
||||||
|
return new Iterable<MatchResult>() {
|
||||||
|
@NonNull
|
||||||
|
public Iterator<MatchResult> iterator() {
|
||||||
|
return new Iterator<MatchResult>() {
|
||||||
|
// Use a matcher internally.
|
||||||
|
final Matcher matcher = pattern.matcher(input);
|
||||||
|
// Keep a match around that supports any interleaving of hasNext/next calls.
|
||||||
|
MatchResult pending;
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
// Lazily fill pending, and avoid calling find() multiple times if the
|
||||||
|
// clients call hasNext() repeatedly before sampling via next().
|
||||||
|
if (pending == null && matcher.find()) {
|
||||||
|
pending = matcher.toMatchResult();
|
||||||
|
}
|
||||||
|
return pending != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MatchResult next() {
|
||||||
|
// Fill pending if necessary (as when clients call next() without
|
||||||
|
// checking hasNext()), throw if not possible.
|
||||||
|
if (!hasNext()) { throw new NoSuchElementException(); }
|
||||||
|
// Consume pending so next call to hasNext() does a find().
|
||||||
|
MatchResult next = pending;
|
||||||
|
pending = null;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Required to satisfy the interface, but unsupported. */
|
||||||
|
public void remove() { throw new UnsupportedOperationException(); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,4 +26,17 @@ public class Logger {
|
|||||||
string.append("null ");
|
string.append("null ");
|
||||||
return string.toString();
|
return string.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void reduce(String content) {
|
||||||
|
if (content==null) {
|
||||||
|
Log.d(tag, "null");
|
||||||
|
} else if (content.length() > 4000) {
|
||||||
|
Log.d(tag, content.substring(0, 4000));
|
||||||
|
reduce(content.substring(4000));
|
||||||
|
} else {
|
||||||
|
Log.d(tag, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ import de.sebse.fuplanner.tools.logging.Logger;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class HTTPService {
|
public class HTTPService {
|
||||||
protected RequestQueue requestQueue;
|
private RequestQueue requestQueue;
|
||||||
private boolean followRedirects;
|
|
||||||
protected Logger log = new Logger(this);
|
protected Logger log = new Logger(this);
|
||||||
|
|
||||||
public HTTPService(Context context) {
|
public HTTPService(Context context) {
|
||||||
@@ -34,7 +33,6 @@ public class HTTPService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public HTTPService(Context context, boolean followRedirects) {
|
public HTTPService(Context context, boolean followRedirects) {
|
||||||
this.followRedirects = followRedirects;
|
|
||||||
requestQueue = Volley.newRequestQueue(context, new BetterHurlStack(followRedirects));
|
requestQueue = Volley.newRequestQueue(context, new BetterHurlStack(followRedirects));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +87,7 @@ public class HTTPService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getBody() throws AuthFailureError {
|
public byte[] getBody() {
|
||||||
if (body==null) {
|
if (body==null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -152,15 +150,4 @@ public class HTTPService {
|
|||||||
};
|
};
|
||||||
requestQueue.add(request);
|
requestQueue.add(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void largeLog(String tag, String content) {
|
|
||||||
if (content==null) {
|
|
||||||
Log.d(tag, "null");
|
|
||||||
} else if (content.length() > 4000) {
|
|
||||||
Log.d(tag, content.substring(0, 4000));
|
|
||||||
largeLog(tag, content.substring(4000));
|
|
||||||
} else {
|
|
||||||
Log.d(tag, content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.sebse.fuplanner.tools.ui;
|
||||||
|
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public class CustomViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
public final View mView;
|
||||||
|
|
||||||
|
public CustomViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
mView = view;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/list"
|
||||||
|
android:name=".fragments.moddetails.ModDetailOverviewFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".fragments.moddetails.ModDetailOverviewFragment">
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
<!-- TODO: Update blank fragment layout -->
|
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
|
||||||
<TextView
|
tools:context=".fragments.moddetails.ModDetailOverviewFragment"
|
||||||
android:layout_width="match_parent"
|
tools:listitem="@layout/list_all_caption" />
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:text="Overview Fragment" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
14
app/src/main/res/layout/list_all_caption.xml
Normal file
14
app/src/main/res/layout/list_all_caption.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/caption"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/text_margin"
|
||||||
|
android:text="Caption"
|
||||||
|
android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline" />
|
||||||
|
</LinearLayout>
|
||||||
38
app/src/main/res/layout/list_moddetails_announcements.xml
Normal file
38
app/src/main/res/layout/list_moddetails_announcements.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="5dip" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:typeface="sans"
|
||||||
|
tools:text="Test this new stuff!" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/publisher"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/title"
|
||||||
|
android:layout_marginTop="5dip"
|
||||||
|
android:textColor="#343434"
|
||||||
|
android:textSize="12sp"
|
||||||
|
tools:text="Peter Müller" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignBaseline="@+id/publisher"
|
||||||
|
android:layout_alignBottom="@+id/publisher"
|
||||||
|
android:textColor="#343434"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
tools:text="20.03.18 18:42 Uhr" />
|
||||||
|
</RelativeLayout>
|
||||||
14
app/src/main/res/layout/list_moddetails_description.xml
Normal file
14
app/src/main/res/layout/list_moddetails_description.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/text_margin"
|
||||||
|
android:text="@string/lorem_ipsum_100"
|
||||||
|
android:textAppearance="?attr/textAppearanceListItem" />
|
||||||
|
</LinearLayout>
|
||||||
@@ -10,4 +10,7 @@
|
|||||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||||
<string name="overview">Overview</string>
|
<string name="overview">Overview</string>
|
||||||
<string name="announcements">Announcements</string>
|
<string name="announcements">Announcements</string>
|
||||||
|
<string name="lorem_ipsum_100">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</string>
|
||||||
|
<string name="description">Description</string>
|
||||||
|
<string name="announcements_count">Announcements (%1$d)</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user