Gradebook Design Update

This commit is contained in:
Sebastian Seedorf
2019-10-22 02:12:52 +02:00
parent 5077898031
commit da03253172
9 changed files with 340 additions and 91 deletions

View File

@@ -13,6 +13,7 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import de.sebse.fuplanner.R; import de.sebse.fuplanner.R;
import de.sebse.fuplanner.services.kvv.types.Grade; import de.sebse.fuplanner.services.kvv.types.Grade;
import de.sebse.fuplanner.services.kvv.types.Gradebook;
import de.sebse.fuplanner.services.kvv.types.Modules; import de.sebse.fuplanner.services.kvv.types.Modules;
import de.sebse.fuplanner.tools.ui.StringViewHolder; import de.sebse.fuplanner.tools.ui.StringViewHolder;
@@ -20,9 +21,12 @@ class ModDetailGradebookAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
private static final int TYPE_TOTAL = 0; private static final int TYPE_TOTAL = 0;
private static final int TYPE_GRADE = 1; private static final int TYPE_GRADE = 1;
private static final int SECTION_GRADE = 0; private static final int SECTION_EXAM = 0;
private static final int SECTION_ASSIGNMENT = 1;
private static final int SECTION_OTHER = 2;
private Modules.Module mValue; private Modules.Module mValue;
private Gradebook.CategorizedGrades mGrades;
private final ArrayList<Pair<Integer, Integer>> mPositionalData; private final ArrayList<Pair<Integer, Integer>> mPositionalData;
ModDetailGradebookAdapter() { ModDetailGradebookAdapter() {
@@ -38,9 +42,32 @@ class ModDetailGradebookAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
private void setModule() { private void setModule() {
mPositionalData.clear(); mPositionalData.clear();
mPositionalData.add(new Pair<>(TYPE_TOTAL, SECTION_GRADE)); if (mValue != null && mValue.gradebook != null) {
for (int i = 0; i < getGradesCount(); i++) { mGrades = mValue.gradebook.getAutoCategorizedGrades();
mPositionalData.add(new Pair<>(TYPE_GRADE, SECTION_GRADE +1024*i)); int size;
size = mGrades.getExams().grades.size();
if (size > 0) {
mPositionalData.add(new Pair<>(setViewType(TYPE_TOTAL, SECTION_EXAM), 0));
for (int i = 0; i < size; i++) {
mPositionalData.add(new Pair<>(setViewType(TYPE_GRADE, SECTION_EXAM), i));
}
}
size = mGrades.getAssignments().grades.size();
if (size > 0) {
mPositionalData.add(new Pair<>(setViewType(TYPE_TOTAL, SECTION_ASSIGNMENT), 0));
for (int i = 0; i < size; i++) {
mPositionalData.add(new Pair<>(setViewType(TYPE_GRADE, SECTION_ASSIGNMENT), i));
}
}
size = mGrades.getOthers().grades.size();
if (size > 0) {
mPositionalData.add(new Pair<>(setViewType(TYPE_TOTAL, SECTION_OTHER), 0));
for (int i = 0; i < size; i++) {
mPositionalData.add(new Pair<>(setViewType(TYPE_GRADE, SECTION_OTHER), i));
}
}
} else {
mGrades = null;
} }
this.notifyDataSetChanged(); this.notifyDataSetChanged();
@@ -53,8 +80,8 @@ class ModDetailGradebookAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
switch (viewType) { switch (viewType) {
case TYPE_TOTAL: case TYPE_TOTAL:
view = LayoutInflater.from(parent.getContext()) view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_all_caption, parent, false); .inflate(R.layout.list_moddetails_gradebook_title, parent, false);
return new StringViewHolder(view); return new GradeTitleViewHolder(view);
case TYPE_GRADE: case TYPE_GRADE:
view = LayoutInflater.from(parent.getContext()) view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_moddetails_gradebook, parent, false); .inflate(R.layout.list_moddetails_gradebook, parent, false);
@@ -69,7 +96,7 @@ class ModDetailGradebookAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
public int getItemViewType(int position) { public int getItemViewType(int position) {
// Note that unlike in ListView adapters, types don't have to be contiguous // Note that unlike in ListView adapters, types don't have to be contiguous
if (position < mPositionalData.size()) if (position < mPositionalData.size())
return mPositionalData.get(position).first; return getViewType(mPositionalData.get(position).first);
else return -1; else return -1;
} }
@@ -79,19 +106,45 @@ class ModDetailGradebookAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
if (mValue == null || position > mPositionalData.size()) if (mValue == null || position > mPositionalData.size())
return; return;
Pair<Integer, Integer> data = mPositionalData.get(position); Pair<Integer, Integer> data = mPositionalData.get(position);
switch (data.first) { int viewType = getViewType(data.first);
int viewSection = getViewSection(data.first);
Gradebook.GradebookOutput gradebook = getViewSectionGradebook(viewSection);
switch (viewType) {
case TYPE_TOTAL: case TYPE_TOTAL:
StringViewHolder h = (StringViewHolder) holder; GradeTitleViewHolder h = (GradeTitleViewHolder) holder;
h.mString.setText(h.mView.getResources().getString(R.string.current_percentage, mValue.getGradebookPercent()*100));
if (gradebook != null) {
String title = "";
switch (viewSection) {
case SECTION_EXAM: title = h.mView.getResources().getString(R.string.exam); break;
case SECTION_ASSIGNMENT: title = h.mView.getResources().getString(R.string.assignments); break;
case SECTION_OTHER: title = h.mView.getResources().getString(R.string.others); break;
}
h.mTitle.setText(title);
Grade bestGrade = gradebook.getBestGrade();
h.mString.setText(h.mView.getResources().getString(
R.string.current_percentage,
gradebook.getUserPointSum(),
gradebook.getMaxPointSum(),
gradebook.getPercentage() * 100,
bestGrade.getPoints(),
bestGrade.getMaxPoints(),
bestGrade.getPoints() / bestGrade.getMaxPoints() * 100,
bestGrade.getItemName()
));
}
break; break;
case TYPE_GRADE: case TYPE_GRADE:
int index = data.second / 1024; int index = data.second;
GradeViewHolder i = (GradeViewHolder) holder; GradeViewHolder i = (GradeViewHolder) holder;
Grade gradebook = mValue.gradebook.get(index);
i.mTitle.setText(gradebook.getItemName()); if (gradebook != null) {
i.mGrade.setText(String.valueOf(gradebook.getPoints())); Grade grade = gradebook.grades.get(index);
i.mGradeMax.setText(String.valueOf(gradebook.getMaxPoints()));
i.mTitle.setText(grade.getItemName());
i.mGrade.setText(String.valueOf(grade.getPoints()));
i.mGradeMax.setText(String.valueOf(grade.getMaxPoints()));
}
break; break;
} }
} }
@@ -101,10 +154,27 @@ class ModDetailGradebookAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
return mPositionalData.size(); return mPositionalData.size();
} }
private int getGradesCount() { private int setViewType(int type, int section) {
if (mValue.gradebook != null) return type * 1024 + section;
return mValue.gradebook.size(); }
return 0;
private int getViewType(int combinedViewType) {
return combinedViewType / 1024;
}
private int getViewSection(int combinedViewType) {
return combinedViewType - getViewType(combinedViewType) * 1024;
}
private Gradebook.GradebookOutput getViewSectionGradebook(int viewSection) {
if (mGrades != null) {
switch (viewSection) {
case SECTION_EXAM: return mGrades.getExams();
case SECTION_ASSIGNMENT: return mGrades.getAssignments();
case SECTION_OTHER: return mGrades.getOthers();
}
}
return null;
} }
@@ -133,4 +203,19 @@ class ModDetailGradebookAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
return super.toString() + " '" + mTitle.getText() + " '" + mGrade.getText() + " '" + mGradeMax.getText() + "'"; return super.toString() + " '" + mTitle.getText() + " '" + mGrade.getText() + " '" + mGradeMax.getText() + "'";
} }
} }
private class GradeTitleViewHolder extends StringViewHolder {
private final TextView mTitle;
GradeTitleViewHolder(View view) {
super(view);
mTitle = view.findViewById(R.id.title);
}
@NonNull
@Override
public String toString() {
return super.toString() + " '" + mTitle.getText();
}
}
} }

View File

@@ -9,31 +9,32 @@ import org.json.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import de.sebse.fuplanner.services.kvv.types.Grade; import de.sebse.fuplanner.services.kvv.types.Grade;
import de.sebse.fuplanner.services.kvv.types.Gradebook;
import de.sebse.fuplanner.services.kvv.types.Modules; import de.sebse.fuplanner.services.kvv.types.Modules;
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;
public class ModulesGradebook extends PartModules<ArrayList<Grade>> { public class ModulesGradebook extends PartModules<Gradebook> {
ModulesGradebook(Login login, ModulesList list, Context context) { ModulesGradebook(Login login, ModulesList list, Context context) {
super(login, list, context); super(login, list, context);
} }
@Override @Override
protected ArrayList<Grade> getPart(Modules.Module module) { protected Gradebook getPart(Modules.Module module) {
return module.gradebook; return module.gradebook;
} }
@Override @Override
protected boolean setPart(Modules.Module module, ArrayList<Grade> part) { protected boolean setPart(Modules.Module module, Gradebook part) {
boolean changed = module.gradebook == null || module.gradebook.hashCode() != part.hashCode(); boolean changed = module.gradebook == null || module.gradebook.hashCode() != part.hashCode();
module.gradebook = part; module.gradebook = part;
return changed; return changed;
} }
@Override @Override
protected void upgradeKVV(final String ID, final NetworkCallback<ArrayList<Grade>> callback, final NetworkErrorCallback errorCallback) { protected void upgradeKVV(final String ID, final NetworkCallback<Gradebook> callback, final NetworkErrorCallback errorCallback) {
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null || !mLogin.getLoginTokenKVV().isAvailable()) { if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null || !mLogin.getLoginTokenKVV().isAvailable()) {
errorCallback.onError(new NetworkError(101504, 500, "Currently running in offline mode!")); errorCallback.onError(new NetworkError(101504, 500, "Currently running in offline mode!"));
return; return;
@@ -44,7 +45,7 @@ public class ModulesGradebook extends PartModules<ArrayList<Grade>> {
errorCallback.onError(new NetworkError(101501, 403, "No gradebook retrieved!")); errorCallback.onError(new NetworkError(101501, 403, "No gradebook retrieved!"));
return; return;
} }
ArrayList<Grade> gradebook = new ArrayList<>(); Gradebook gradebook = new Gradebook();
JSONArray sites; JSONArray sites;
try { try {
JSONObject json = new JSONObject(body); JSONObject json = new JSONObject(body);
@@ -62,7 +63,7 @@ public class ModulesGradebook extends PartModules<ArrayList<Grade>> {
String itemName = site.optString("itemName", null); String itemName = site.optString("itemName", null);
double maxPoints = site.optDouble("points", -1); double maxPoints = site.optDouble("points", -1);
gradebook.add(0, new Grade(itemName, grade, maxPoints)); gradebook.addGrade(new Grade(itemName, grade, maxPoints));
} catch (JSONException e) { } catch (JSONException e) {
log.e(new NetworkError(101505, 403, "Cannot parse gradebook!")); log.e(new NetworkError(101505, 403, "Cannot parse gradebook!"));
log.e("ID:", i, "JSON:", sites); log.e("ID:", i, "JSON:", sites);
@@ -73,14 +74,14 @@ public class ModulesGradebook extends PartModules<ArrayList<Grade>> {
callback.onResponse(gradebook); callback.onResponse(gradebook);
}, error -> { }, error -> {
if (error.networkResponse.statusCode == 400) if (error.networkResponse.statusCode == 400)
callback.onResponse(new ArrayList<>()); callback.onResponse(new Gradebook());
else else
errorCallback.onError(new NetworkError(101503, error.networkResponse.statusCode, "Cannot get gradebook!")); errorCallback.onError(new NetworkError(101503, error.networkResponse.statusCode, "Cannot get gradebook!"));
}); });
} }
@Override @Override
protected void upgradeBB(String ID, NetworkCallback<ArrayList<Grade>> callback, NetworkErrorCallback errorCallback) { protected void upgradeBB(String ID, NetworkCallback<Gradebook> callback, NetworkErrorCallback errorCallback) {
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null || !mLogin.getLoginTokenBB().isAvailable()) { if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null || !mLogin.getLoginTokenBB().isAvailable()) {
errorCallback.onError(new NetworkError(101510, 500, "Currently running in offline mode!")); errorCallback.onError(new NetworkError(101510, 500, "Currently running in offline mode!"));
return; return;
@@ -117,7 +118,7 @@ public class ModulesGradebook extends PartModules<ArrayList<Grade>> {
return; return;
} }
ArrayList<Grade> result = new ArrayList<>(); Gradebook result = new Gradebook();
for (int i = 0; i < grades.length(); i++) { for (int i = 0; i < grades.length(); i++) {
for (int j = 0; j < gradeColumns.length(); j++) { for (int j = 0; j < gradeColumns.length(); j++) {
try { try {
@@ -133,7 +134,7 @@ public class ModulesGradebook extends PartModules<ArrayList<Grade>> {
JSONObject score = column.optJSONObject("score"); JSONObject score = column.optJSONObject("score");
double maxPoints = score != null ? score.optDouble("possible", 0) : 0; double maxPoints = score != null ? score.optDouble("possible", 0) : 0;
result.add(new Grade(name, points, maxPoints)); result.addGrade(new Grade(name, points, maxPoints));
} catch (JSONException e) { } catch (JSONException e) {
log.e(new NetworkError(101515, 400, "Cannot parse grades!")); log.e(new NetworkError(101515, 400, "Cannot parse grades!"));
log.e("ID:", i, "JSON-grades:", grades); log.e("ID:", i, "JSON-grades:", grades);
@@ -147,7 +148,7 @@ public class ModulesGradebook extends PartModules<ArrayList<Grade>> {
}, error -> errorCallback.onError(new NetworkError(101516, error.networkResponse.statusCode, "Cannot get gradebook columns!"))); }, error -> errorCallback.onError(new NetworkError(101516, error.networkResponse.statusCode, "Cannot get gradebook columns!")));
}, error -> { }, error -> {
if (error.networkResponse.statusCode == 403) if (error.networkResponse.statusCode == 403)
callback.onResponse(new ArrayList<>()); callback.onResponse(new Gradebook());
else else
errorCallback.onError(new NetworkError(101517, error.networkResponse.statusCode, "Cannot get gradebook entries!")); errorCallback.onError(new NetworkError(101517, error.networkResponse.statusCode, "Cannot get gradebook entries!"));
}); });

View File

@@ -23,6 +23,7 @@ import de.sebse.fuplanner.services.kvv.types.Assignment;
import de.sebse.fuplanner.services.kvv.types.AssignmentList; import de.sebse.fuplanner.services.kvv.types.AssignmentList;
import de.sebse.fuplanner.services.kvv.types.EventList; import de.sebse.fuplanner.services.kvv.types.EventList;
import de.sebse.fuplanner.services.kvv.types.Grade; import de.sebse.fuplanner.services.kvv.types.Grade;
import de.sebse.fuplanner.services.kvv.types.Gradebook;
import de.sebse.fuplanner.services.kvv.types.Modules; import de.sebse.fuplanner.services.kvv.types.Modules;
import de.sebse.fuplanner.services.kvv.types.Resource; import de.sebse.fuplanner.services.kvv.types.Resource;
import de.sebse.fuplanner.tools.CustomNotificationManager; import de.sebse.fuplanner.tools.CustomNotificationManager;
@@ -126,7 +127,7 @@ public class KVVSyncAdapter extends AbstractThreadedSyncAdapter {
final ArrayList<Announcement> announcements = module.announcements; final ArrayList<Announcement> announcements = module.announcements;
final AssignmentList assignments = module.assignments; final AssignmentList assignments = module.assignments;
final EventList events = module.events; final EventList events = module.events;
final ArrayList<Grade> gradebook = module.gradebook; final Gradebook gradebook = module.gradebook;
final ArrayList<Resource> resources = module.resources; final ArrayList<Resource> resources = module.resources;
mKVV.modules().details().recv(module, success1 -> { mKVV.modules().details().recv(module, success1 -> {
if (success1.second) { if (success1.second) {

View File

@@ -0,0 +1,138 @@
package de.sebse.fuplanner.services.kvv.types;
import androidx.annotation.NonNull;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class Gradebook implements Serializable, Iterable<Grade> {
private ArrayList<Grade> gradebook = new ArrayList<>();
private final static String[] EXAM_KEYWORDS = new String[] {"exam", "klausur", "prüfung"};
private final static String[] ASSIGNMENT_KEYWORDS = new String[] {"übung", "assignment", "blatt", "sheet", "exercise"};
public void addGrade(Grade grade) {
gradebook.add(0, grade);
}
public CategorizedGrades getAutoCategorizedGrades() {
ArrayList<Grade> exams = new ArrayList<>();
ArrayList<Grade> assignments = new ArrayList<>();
ArrayList<Grade> others = new ArrayList<>();
for (Grade grade : gradebook) {
boolean found = false;
String name = grade.getItemName().toLowerCase();
for (String keyword : EXAM_KEYWORDS) {
if (name.contains(keyword)) {
exams.add(grade);
found = true;
break;
}
}
if (found) continue;
for (String keyword : ASSIGNMENT_KEYWORDS) {
if (name.contains(keyword)) {
assignments.add(grade);
found = true;
break;
}
}
if (found) continue;
others.add(grade);
}
return new CategorizedGrades(exams, assignments, others);
}
public GradebookOutput getUncategorizedGrades() {
return new GradebookOutput(gradebook);
}
@NonNull
@Override
public Iterator<Grade> iterator() {
return gradebook.iterator();
}
public class CategorizedGrades {
private GradebookOutput exams;
private GradebookOutput assignments;
private GradebookOutput others;
private CategorizedGrades(List<Grade> exams, List<Grade> assignments, List<Grade> others) {
this.exams = new GradebookOutput(exams);
this.assignments = new GradebookOutput(assignments);
this.others = new GradebookOutput(others);
}
public GradebookOutput getExams() {
return exams;
}
public GradebookOutput getAssignments() {
return assignments;
}
public GradebookOutput getOthers() {
return others;
}
}
public class GradebookOutput {
public List<Grade> grades;
private GradebookOutput(List<Grade> grades) {
this.grades = Collections.unmodifiableList(grades);
}
public float getPercentage() {
float maxPoints = 0;
float userPoints = 0;
if (grades != null) {
for (Grade g : grades){
maxPoints += g.getMaxPoints();
userPoints += g.getPoints();
}
}
if (maxPoints == 0)
return 0;
return userPoints / maxPoints;
}
public float getMaxPointSum() {
float maxPoints = 0;
if (grades != null) {
for (Grade g : grades){
maxPoints += g.getMaxPoints();
}
}
return maxPoints;
}
public float getUserPointSum() {
float userPoints = 0;
if (grades != null) {
for (Grade g : grades){
userPoints += g.getPoints();
}
}
return userPoints;
}
public Grade getBestGrade() {
Grade bestGrade = null;
double bestValue = -1;
if (grades != null) {
for (Grade g : grades){
double perc = g.getPoints() / g.getMaxPoints();
if (perc > bestValue) {
bestValue = perc;
bestGrade = g;
}
}
}
return bestGrade;
}
}
}

View File

@@ -178,23 +178,9 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
@Nullable public ArrayList<Announcement> announcements; @Nullable public ArrayList<Announcement> announcements;
@Nullable public AssignmentList assignments; @Nullable public AssignmentList assignments;
@Nullable public EventList events; @Nullable public EventList events;
@Nullable public ArrayList<Grade> gradebook; @Nullable public Gradebook gradebook;
@Nullable public ArrayList<Resource> resources; @Nullable public ArrayList<Resource> resources;
public float getGradebookPercent(){
float maxPoint = 0;
float userPoint = 0;
if (gradebook != null) {
for (Grade g : gradebook){
maxPoint += g.getMaxPoints();
userPoint += g.getPoints();
}
}
if (maxPoint == 0)
return 0;
return userPoint/maxPoint;
}
private Module(@Nullable Semester semester, @NotNull HashSet<String> lvNumber, @NotNull String title, @NotNull LinkedHashSet<Lecturer> lecturer, @Nullable String type, @Nullable String description, @NotNull String ID, int moduleType) { private Module(@Nullable Semester semester, @NotNull HashSet<String> lvNumber, @NotNull String title, @NotNull LinkedHashSet<Lecturer> lecturer, @Nullable String type, @Nullable String description, @NotNull String ID, int moduleType) {
title = title.replaceAll("(.*?) (S[0-9]{2}|W[0-9/]{5})", "$1"); title = title.replaceAll("(.*?) (S[0-9]{2}|W[0-9/]{5})", "$1");

View File

@@ -1,6 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_margin="@dimen/cardview_margin"
card_view:cardElevation="@dimen/cardview_elevation">
<RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
@@ -46,4 +52,5 @@
style="@style/FUTheme.itemValue" style="@style/FUTheme.itemValue"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
tools:text="10" /> tools:text="10" />
</RelativeLayout> </RelativeLayout>
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/cardview_margin"
android:layout_marginStart="@dimen/cardview_margin"
android:layout_marginTop="16dp"
android:layout_marginRight="@dimen/cardview_margin"
android:layout_marginEnd="@dimen/cardview_margin"
tools:text="Caption"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Headline" />
<TextView
android:id="@+id/string"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/cardview_margin"
android:layout_marginStart="@dimen/cardview_margin"
android:layout_marginBottom="4dp"
android:layout_marginRight="@dimen/cardview_margin"
android:layout_marginEnd="@dimen/cardview_margin"
tools:text="Caption"
style="@style/FUTheme.itemValue" />
</LinearLayout>

View File

@@ -28,7 +28,7 @@
<string name="no_items_available">Keine Einträge vorhanden!</string> <string name="no_items_available">Keine Einträge vorhanden!</string>
<string name="events">Veranstaltungen</string> <string name="events">Veranstaltungen</string>
<string name="gradebook">Noten</string> <string name="gradebook">Noten</string>
<string name="current_percentage">Aktuelle Prozentzahl: %1$.2f \%%</string> <string name="current_percentage">Punkte: %1$.1f / %2$.1f\nProzentsatz: %3$.1f \%%\nBeste Note: %4$.1f / %5$.1f - %6$.1f \%% (%7$s)</string>
<string name="offline_mode">Offline-Modus</string> <string name="offline_mode">Offline-Modus</string>
<string name="refresh_failed">Aktualisieren fehlgeschlagen…</string> <string name="refresh_failed">Aktualisieren fehlgeschlagen…</string>
<string name="share_intent">Hey, schau\' dir die neue KVV App an: %1$s</string> <string name="share_intent">Hey, schau\' dir die neue KVV App an: %1$s</string>

View File

@@ -30,7 +30,7 @@
<string name="no_items_available">No items available!</string> <string name="no_items_available">No items available!</string>
<string name="events">Events</string> <string name="events">Events</string>
<string name="gradebook">Gradebook</string> <string name="gradebook">Gradebook</string>
<string name="current_percentage">Current Percentage: %1$.2f \%%</string> <string name="current_percentage">Points: %1$.1f / %2$.1f\nPercentage: %3$.1f \%%\nBest Grade: %4$.1f / %5$.1f - %6$.1f \%% (%7$s)</string>
<string name="offline_mode">Offline Mode</string> <string name="offline_mode">Offline Mode</string>
<string name="refresh_failed">Refresh failed…</string> <string name="refresh_failed">Refresh failed…</string>
<string name="share_intent">Hey, check out the new KVV app: %1$s</string> <string name="share_intent">Hey, check out the new KVV app: %1$s</string>