Implementing Pull to Refresh (#28)

* Add swipe refresh layout
* Remove indicator and change border position
* Add snackbar for new grades and rename classes of synchronization
* Add info of the number of grades
* Add grades average average
* Add alert of new grades
* Fix crash while refreshing
* Add disappearing alerts
* Optimize res and fix crash
* Update API to version 27
This commit is contained in:
Rafał Borcz 2017-10-27 17:05:00 +02:00 committed by Mikołaj Pich
parent fe54fa71f3
commit f6e29490c3
35 changed files with 621 additions and 224 deletions

View File

@ -4,13 +4,13 @@ apply plugin: "io.github.ddimtirov.codacy"
apply plugin: 'org.greenrobot.greendao'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
compileSdkVersion 27
buildToolsVersion "27.0.0"
defaultConfig {
applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 15
targetSdkVersion 26
targetSdkVersion 27
versionCode 1
versionName "0.1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@ -39,21 +39,19 @@ android {
}
greendao {
schemaVersion 10
schemaVersion 13
generateTests = true
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:26.0.1'
compile 'com.android.support:appcompat-v7:27.0.0'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:26.0.1'
compile 'com.android.support:support-vector-drawable:26.0.1'
compile 'com.android.support:support-v4:26.0.1'
compile 'com.android.support:recyclerview-v7:26.0.1'
compile 'com.android.support:cardview-v7:26.0.1'
compile 'com.firebase:firebase-jobdispatcher:0.8.1'
compile 'com.android.support:design:27.0.0'
compile 'com.android.support:support-vector-drawable:27.0.0'
compile 'com.android.support:support-v4:27.0.0'
compile 'com.android.support:recyclerview-v7:27.0.0'
compile 'com.android.support:cardview-v7:27.0.0'
compile 'com.firebase:firebase-jobdispatcher:0.8.4'
compile 'com.thoughtbot:expandablerecyclerview:1.3'
compile 'org.apache.commons:commons-lang3:3.6'
compile 'org.apache.commons:commons-collections4:4.1'
@ -71,7 +69,7 @@ dependencies {
androidTestCompile('com.android.support.test.espresso:espresso-core:3.0.1', {
exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestCompile 'com.android.support:support-annotations:26.0.1'
androidTestCompile 'com.android.support:support-annotations:27.0.0'
androidTestCompile 'com.android.support.test:runner:1.0.1'
androidTestCompile 'com.android.support.test:rules:1.0.1'
androidTestCompile 'org.hamcrest:hamcrest-library:1.3'

View File

@ -0,0 +1,50 @@
package io.github.wulkanowy.dao;
import android.support.test.InstrumentationRegistry;
import org.greenrobot.greendao.database.Database;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import io.github.wulkanowy.dao.entities.DaoMaster;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.dao.entities.Grade;
public class DatabaseAccessTest extends DatabaseAccess {
private static DaoSession daoSession;
@BeforeClass
public static void setUpClass() {
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(InstrumentationRegistry.getTargetContext()
, "wulkanowyTest-database");
Database database = devOpenHelper.getWritableDb();
daoSession = new DaoMaster(database).newSession();
}
@Before
public void setUp() {
daoSession.getGradeDao().deleteAll();
daoSession.clear();
}
@Test
public void getNewGradesTest() {
daoSession.getGradeDao().insert(new Grade()
.setIsNew(true));
Assert.assertEquals(1, DatabaseAccess.getNewGrades(daoSession).size());
}
@AfterClass
public static void cleanUp() {
daoSession.getAccountDao().deleteAll();
daoSession.getGradeDao().deleteAll();
daoSession.getSubjectDao().deleteAll();
daoSession.clear();
}
}

View File

@ -40,7 +40,7 @@
android:label="@string/activity_dashboard_text" />
<service
android:name=".services.jobs.GradesSync$GradeJob"
android:name=".services.jobs.GradeJob$GradeService"
android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />

View File

@ -3,12 +3,9 @@ package io.github.wulkanowy.activity.dashboard.grades;
import android.app.Activity;
import android.app.DialogFragment;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
@ -21,16 +18,17 @@ import java.util.List;
import io.github.wulkanowy.R;
import io.github.wulkanowy.dao.entities.Grade;
import static android.view.animation.Animation.RELATIVE_TO_SELF;
import io.github.wulkanowy.utilities.AverageCalculator;
public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.SubjectViewHolder, GradesAdapter.GradeViewHolder> {
private Activity activity;
public GradesAdapter(List<? extends ExpandableGroup> groups, Context context) {
private int numberOfNotReadGrade;
public GradesAdapter(List<? extends ExpandableGroup> groups, Activity activity) {
super(groups);
activity = (Activity) context;
this.activity = activity;
}
@Override
@ -59,80 +57,42 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.S
private TextView subjectName;
private ImageView indicatorDown;
private TextView numberOfGrades;
private ImageView indicatorUp;
private TextView averageGrades;
private ImageView subjectAlertNewGrades;
public SubjectViewHolder(View itemView) {
super(itemView);
subjectName = itemView.findViewById(R.id.subject_text);
indicatorDown = itemView.findViewById(R.id.group_indicator_down);
indicatorUp = itemView.findViewById(R.id.group_indicator_up);
numberOfGrades = itemView.findViewById(R.id.subject_number_of_grades);
subjectAlertNewGrades = itemView.findViewById(R.id.subject_new_grades_alert);
averageGrades = itemView.findViewById(R.id.subject_grades_average);
subjectAlertNewGrades.setVisibility(View.INVISIBLE);
}
public void bind(ExpandableGroup group) {
subjectName.setText(group.getTitle());
int volumeGrades = group.getItemCount();
List<Grade> gradeList = group.getItems();
float average = AverageCalculator.calculate(gradeList);
if (isGroupExpanded(group)) {
indicatorDown.setVisibility(View.INVISIBLE);
indicatorUp.setVisibility(View.VISIBLE);
itemView.setTag(group.getTitle());
if (average < 0) {
averageGrades.setText(R.string.info_no_average);
} else {
indicatorDown.setVisibility(View.VISIBLE);
indicatorUp.setVisibility(View.INVISIBLE);
}
averageGrades.setText(activity.getResources().getString(R.string.info_average_grades, average));
}
subjectName.setText(group.getTitle());
numberOfGrades.setText(activity.getResources().getQuantityString(R.plurals.numberOfGrades, volumeGrades, volumeGrades));
@Override
public void expand() {
RotateAnimation rotate =
new RotateAnimation(-360, -180, RELATIVE_TO_SELF, 0.5f, RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(300);
rotate.setFillAfter(false);
rotate.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//Empty method definition
for (Grade grade : gradeList) {
if (!grade.getRead()) {
subjectAlertNewGrades.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animation animation) {
indicatorDown.setVisibility(View.INVISIBLE);
indicatorUp.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {
//Empty method definition
}
});
indicatorDown.setAnimation(rotate);
}
@Override
public void collapse() {
RotateAnimation rotate =
new RotateAnimation(360, 180, RELATIVE_TO_SELF, 0.5f, RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(300);
rotate.setFillAfter(false);
rotate.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//Empty method definition
}
@Override
public void onAnimationEnd(Animation animation) {
indicatorDown.setVisibility(View.VISIBLE);
indicatorUp.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {
//Empty method definition
}
});
indicatorUp.setAnimation(rotate);
}
}
@ -144,32 +104,29 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.S
private TextView dateGrade;
private Grade grade;
private ImageView alertNewGrade;
public GradeViewHolder(final View itemView) {
private View itemView;
private Grade gradeItem;
public GradeViewHolder(View itemView) {
super(itemView);
this.itemView = itemView;
gradeValue = itemView.findViewById(R.id.grade_text);
descriptionGrade = itemView.findViewById(R.id.description_grade_text);
dateGrade = itemView.findViewById(R.id.grade_date_text);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
GradesDialogFragment gradesDialogFragment = GradesDialogFragment.newInstance(grade);
gradesDialogFragment.setStyle(DialogFragment.STYLE_NO_TITLE, 0);
gradesDialogFragment.show(activity.getFragmentManager(), grade.toString());
}
});
alertNewGrade = itemView.findViewById(R.id.grade_new_grades_alert);
}
public void bind(Grade grade) {
this.grade = grade;
gradeValue.setText(grade.getValue());
gradeValue.setBackgroundResource(grade.getValueColor());
dateGrade.setText(grade.getDate());
gradeItem = grade;
if (grade.getDescription().equals("") || grade.getDescription() == null) {
if (!grade.getSymbol().equals("")) {
if (grade.getDescription() == null || "".equals(grade.getDescription())) {
if (!"".equals(grade.getSymbol())) {
descriptionGrade.setText(grade.getSymbol());
} else {
descriptionGrade.setText(R.string.noDescription_text);
@ -178,6 +135,37 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter<GradesAdapter.S
descriptionGrade.setText(grade.getDescription());
}
if (gradeItem.getRead()) {
alertNewGrade.setVisibility(View.INVISIBLE);
} else {
alertNewGrade.setVisibility(View.VISIBLE);
numberOfNotReadGrade++;
}
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
GradesDialogFragment gradesDialogFragment = GradesDialogFragment.newInstance(gradeItem);
gradesDialogFragment.setStyle(DialogFragment.STYLE_NO_TITLE, 0);
gradesDialogFragment.show(activity.getFragmentManager(), gradeItem.toString());
if (!gradeItem.getRead()) {
numberOfNotReadGrade--;
}
if (numberOfNotReadGrade == 0) {
View subjectView = activity.findViewById(R.id.subject_grade_recycler).findViewWithTag(gradeItem.getSubject());
View subjectAlertNewGrade = subjectView.findViewById(R.id.subject_new_grades_alert);
subjectAlertNewGrade.setVisibility(View.INVISIBLE);
}
gradeItem.setRead(true);
gradeItem.setIsNew(false);
gradeItem.update();
alertNewGrade.setVisibility(View.INVISIBLE);
}
});
}
}
}

View File

@ -3,70 +3,99 @@ package io.github.wulkanowy.activity.dashboard.grades;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
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.Toast;
import java.util.ArrayList;
import java.util.List;
import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.WulkanowyApp;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.dao.DatabaseAccess;
import io.github.wulkanowy.dao.entities.Account;
import io.github.wulkanowy.dao.entities.AccountDao;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.dao.entities.Grade;
import io.github.wulkanowy.dao.entities.Subject;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization;
import io.github.wulkanowy.services.jobs.VulcanJobHelper;
import io.github.wulkanowy.utilities.ConnectionUtilities;
public class GradesFragment extends Fragment {
private List<SubjectWithGrades> subjectWithGradesList = new ArrayList<>();
private SwipeRefreshLayout swipeRefreshLayout;
private View view;
private RefreshTask refreshTask;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_grades, container, false);
DaoSession daoSession = ((WulkanowyApp) getActivity().getApplication()).getDaoSession();
swipeRefreshLayout = view.findViewById(R.id.grade_swipe_refresh);
swipeRefreshLayout.setColorSchemeResources(android.R.color.black,
android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
if (!ConnectionUtilities.isOnline(view.getContext())) {
swipeRefreshLayout.setRefreshing(false);
Toast.makeText(view.getContext(), R.string.noInternet_text, Toast.LENGTH_SHORT).show();
} else {
refreshTask = new RefreshTask();
refreshTask.execute(((WulkanowyApp) getActivity().getApplication()).getDaoSession());
}
}
});
if (new ArrayList<>().equals(subjectWithGradesList)) {
createExpListView();
new GradesTask(daoSession).execute();
new GradesTask().execute(((WulkanowyApp) getActivity().getApplication()).getDaoSession());
} else if (subjectWithGradesList.size() > 0) {
createExpListView();
view.findViewById(R.id.loadingPanel).setVisibility(View.GONE);
}
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (refreshTask != null && refreshTask.getStatus() == AsyncTask.Status.RUNNING) {
refreshTask.cancel(true);
}
}
private void createExpListView() {
RecyclerView recyclerView = view.findViewById(R.id.subject_grade_recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
GradesAdapter gradesAdapter = new GradesAdapter(subjectWithGradesList, view.getContext());
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
GradesAdapter gradesAdapter = new GradesAdapter(subjectWithGradesList, getActivity());
recyclerView.setAdapter(gradesAdapter);
}
private class GradesTask extends AsyncTask<Void, Void, Void> {
private void prepareSubjectsWithGradesList(DaoSession daoSession) {
subjectWithGradesList = new ArrayList<>();
private DaoSession daoSession;
GradesTask(DaoSession daoSession) {
this.daoSession = daoSession;
}
@Override
protected Void doInBackground(Void... params) {
long userId = getActivity().getSharedPreferences("LoginData", Context.MODE_PRIVATE)
long userId = getContext().getSharedPreferences("LoginData", Context.MODE_PRIVATE)
.getLong("userId", 0);
AccountDao accountDao = daoSession.getAccountDao();
@ -79,6 +108,13 @@ public class GradesFragment extends Fragment {
subjectWithGradesList.add(subjectWithGrades);
}
}
}
private class GradesTask extends AsyncTask<DaoSession, Void, Void> {
@Override
protected Void doInBackground(DaoSession... params) {
prepareSubjectsWithGradesList(params[0]);
return null;
}
@ -86,8 +122,51 @@ public class GradesFragment extends Fragment {
super.onPostExecute(result);
createExpListView();
view.findViewById(R.id.loadingPanel).setVisibility(View.GONE);
}
}
private class RefreshTask extends AsyncTask<DaoSession, Void, Boolean> {
@Override
protected Boolean doInBackground(DaoSession... params) {
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession());
try {
vulcanSynchronization.loginCurrentUser(getContext(), params[0], new Vulcan());
vulcanSynchronization.syncGrades();
prepareSubjectsWithGradesList(params[0]);
return true;
} catch (Exception e) {
Log.e(VulcanJobHelper.DEBUG_TAG, "There was a synchronization problem", e);
return false;
}
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result) {
prepareSubjectsWithGradesList(((WulkanowyApp) getActivity().getApplication()).getDaoSession());
createExpListView();
swipeRefreshLayout.setRefreshing(false);
int volumeGrades = DatabaseAccess.getNewGrades(((WulkanowyApp) getActivity().getApplication()).getDaoSession()).size();
if (volumeGrades == 0) {
Snackbar.make(getActivity().findViewById(R.id.fragment_container),
R.string.snackbar_no_grades,
Snackbar.LENGTH_SHORT).show();
} else {
Snackbar.make(getActivity().findViewById(R.id.fragment_container),
getString(R.string.snackbar_new_grade, volumeGrades),
Snackbar.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getContext(), R.string.refresh_error_text, Toast.LENGTH_SHORT).show();
swipeRefreshLayout.setRefreshing(false);
}
}
}
}

View File

@ -19,7 +19,7 @@ import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization;
import io.github.wulkanowy.services.jobs.GradesSync;
import io.github.wulkanowy.services.jobs.GradeJob;
import io.github.wulkanowy.utilities.ConnectionUtilities;
public class LoginTask extends AsyncTask<String, Integer, Integer> {
@ -74,7 +74,7 @@ public class LoginTask extends AsyncTask<String, Integer, Integer> {
protected void onPostExecute(Integer messageID) {
super.onPostExecute(messageID);
GradesSync gradesSync = new GradesSync();
GradeJob gradesSync = new GradeJob();
gradesSync.scheduledJob(activity);
progress.dismiss();

View File

@ -8,7 +8,7 @@ import android.widget.Toast;
import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.dashboard.DashboardActivity;
import io.github.wulkanowy.activity.main.MainActivity;
import io.github.wulkanowy.services.jobs.GradesSync;
import io.github.wulkanowy.services.jobs.GradeJob;
import io.github.wulkanowy.utilities.ConnectionUtilities;
public class LoadingTask extends AsyncTask<Void, Void, Boolean> {
@ -42,7 +42,7 @@ public class LoadingTask extends AsyncTask<Void, Void, Boolean> {
Intent intent = new Intent(context, MainActivity.class);
context.startActivity(intent);
} else {
GradesSync gradesSync = new GradesSync();
GradeJob gradesSync = new GradeJob();
gradesSync.scheduledJob(context);
Intent intent = new Intent(context, DashboardActivity.class);

View File

@ -0,0 +1,20 @@
package io.github.wulkanowy.dao;
import org.greenrobot.greendao.query.Query;
import java.util.List;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.dao.entities.Grade;
import io.github.wulkanowy.dao.entities.GradeDao;
public abstract class DatabaseAccess {
public static List<Grade> getNewGrades(DaoSession daoSession) {
Query<Grade> gradeQuery = daoSession.getGradeDao().queryBuilder()
.where(GradeDao.Properties.IsNew.eq(1))
.build();
return gradeQuery.list();
}
}

View File

@ -15,12 +15,24 @@ public abstract class EntitiesCompare {
.removeAll(newList, oldList));
List<Grade> updatedList = new ArrayList<>(CollectionUtils
.removeAll(newList, addedOrUpdatedGradeList));
List<Grade> lastList = new ArrayList<>();
for (Grade grade : addedOrUpdatedGradeList) {
grade.setIsNew(true);
if (oldList.size() != 0) {
grade.setRead(false);
}
updatedList.add(grade);
}
return updatedList;
for (Grade grade : updatedList) {
for (Grade grade1 : oldList) {
if (grade.equals(grade1)) {
grade.setRead(grade1.getRead());
}
}
lastList.add(grade);
}
return lastList;
}
}

View File

@ -5,6 +5,7 @@ import android.os.Parcelable;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
@ -12,7 +13,10 @@ import org.greenrobot.greendao.annotation.Property;
import io.github.wulkanowy.R;
@Entity(nameInDb = "Grades")
@Entity(
nameInDb = "Grades",
active = true
)
public class Grade implements Parcelable {
@Id(autoincrement = true)
@ -54,14 +58,18 @@ public class Grade implements Parcelable {
@Property(nameInDb = "IS_NEW")
private boolean isNew = false;
@Property(nameInDb = "READ")
private boolean read = true;
protected Grade(Parcel source) {
value = source.readString();
}
@Generated(hash = 1154096520)
@Generated(hash = 568899968)
public Grade(Long id, Long subjectId, Long userId, String subject, String value,
String color, String symbol, String description, String weight,
String date, String teacher, String semester, boolean isNew) {
String date, String teacher, String semester, boolean isNew,
boolean read) {
this.id = id;
this.subjectId = subjectId;
this.userId = userId;
@ -75,6 +83,7 @@ public class Grade implements Parcelable {
this.teacher = teacher;
this.semester = semester;
this.isNew = isNew;
this.read = read;
}
@Generated(hash = 2042976393)
@ -95,8 +104,8 @@ public class Grade implements Parcelable {
parcel.writeString(description);
parcel.writeString(weight);
parcel.writeString(date);
parcel.writeString(value);
parcel.writeString(value);
parcel.writeString(teacher);
parcel.writeString(semester);
}
public static final Creator<Grade> CREATOR = new Creator<Grade>() {
@ -111,6 +120,18 @@ public class Grade implements Parcelable {
}
};
/**
* Used to resolve relations
*/
@Generated(hash = 2040040024)
private transient DaoSession daoSession;
/**
* Used for active entity operations.
*/
@Generated(hash = 681281562)
private transient GradeDao myDao;
public int getValueColor() {
String replacedString = value.replaceAll("[^0-9]", "");
@ -284,7 +305,62 @@ public class Grade implements Parcelable {
return this.isNew;
}
public void setIsNew(boolean isNew) {
public Grade setIsNew(boolean isNew) {
this.isNew = isNew;
return this;
}
public boolean getRead() {
return this.read;
}
public Grade setRead(boolean read) {
this.read = read;
return this;
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 128553479)
public void delete() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.delete(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 1942392019)
public void refresh() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.refresh(this);
}
/**
* Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}.
* Entity must attached to an entity context.
*/
@Generated(hash = 713229351)
public void update() {
if (myDao == null) {
throw new DaoException("Entity is detached from DAO context");
}
myDao.update(this);
}
/**
* called by internal mechanisms, do not call yourself.
*/
@Generated(hash = 1187286414)
public void __setDaoSession(DaoSession daoSession) {
this.daoSession = daoSession;
myDao = daoSession != null ? daoSession.getGradeDao() : null;
}
}

View File

@ -1,6 +1,9 @@
package io.github.wulkanowy.services;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.dao.entities.DaoSession;
@ -38,4 +41,28 @@ public class LoginSession {
this.daoSession = daoSession;
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LoginSession that = (LoginSession) o;
return new EqualsBuilder()
.append(userId, that.userId)
.append(vulcan, that.vulcan)
.append(daoSession, that.daoSession)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(userId)
.append(vulcan)
.append(daoSession)
.toHashCode();
}
}

View File

@ -12,7 +12,7 @@ import io.github.wulkanowy.api.login.LoginErrorException;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.jobs.VulcanSync;
import io.github.wulkanowy.services.jobs.VulcanJobHelper;
import io.github.wulkanowy.services.synchronisation.AccountSynchronisation;
import io.github.wulkanowy.services.synchronisation.GradesSynchronisation;
import io.github.wulkanowy.services.synchronisation.SubjectsSynchronisation;
@ -47,7 +47,7 @@ public class VulcanSynchronization {
gradesSynchronisation.sync(loginSession);
return true;
} catch (Exception e) {
Log.e(VulcanSync.DEBUG_TAG, "Synchronisation of grades failed", e);
Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of grades failed", e);
return false;
}
}
@ -60,7 +60,7 @@ public class VulcanSynchronization {
syncGrades();
return true;
} catch (Exception e) {
Log.e(VulcanSync.DEBUG_TAG, "Synchronisation of subjects failed", e);
Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of subjects failed", e);
return false;
}
}

View File

@ -19,7 +19,7 @@ import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization;
public class GradesSync extends VulcanSync {
public class GradeJob extends VulcanJobHelper {
public static final String UNIQUE_TAG = "GradesSync34512";
@ -31,7 +31,7 @@ public class GradesSync extends VulcanSync {
protected Job createJob(FirebaseJobDispatcher dispatcher) {
return dispatcher.newJobBuilder()
.setLifetime(Lifetime.FOREVER)
.setService(GradeJob.class)
.setService(GradeService.class)
.setTag(UNIQUE_TAG)
.setRecurring(true)
.setTrigger(Trigger.executionWindow(DEFAULT_INTERVAL_START, DEFAULT_INTERVAL_END))
@ -41,7 +41,7 @@ public class GradesSync extends VulcanSync {
.build();
}
public static class GradeJob extends VulcanJob {
public static class GradeService extends VulcanService {
@Override
public void workToBePerformed() throws CryptoException, BadCredentialsException,

View File

@ -19,7 +19,7 @@ import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization;
public class SubjectsSync extends VulcanSync {
public class SubjectJob extends VulcanJobHelper {
public static final String UNIQUE_TAG = "SubjectsSync34512";
@ -31,7 +31,7 @@ public class SubjectsSync extends VulcanSync {
protected Job createJob(FirebaseJobDispatcher dispatcher) {
return dispatcher.newJobBuilder()
.setLifetime(Lifetime.UNTIL_NEXT_BOOT)
.setService(SubjectJob.class)
.setService(SubjectService.class)
.setTag(UNIQUE_TAG)
.setRecurring(false)
.setTrigger(Trigger.executionWindow(DEFAULT_INTERVAL_START, DEFAULT_INTERVAL_END))
@ -41,7 +41,7 @@ public class SubjectsSync extends VulcanSync {
.build();
}
private class SubjectJob extends VulcanJob {
private class SubjectService extends VulcanService {
@Override
public void workToBePerformed() throws CryptoException, BadCredentialsException,

View File

@ -7,7 +7,7 @@ import com.firebase.jobdispatcher.FirebaseJobDispatcher;
import com.firebase.jobdispatcher.GooglePlayDriver;
import com.firebase.jobdispatcher.Job;
public abstract class VulcanSync {
public abstract class VulcanJobHelper {
public static final String DEBUG_TAG = "SynchronizationService";

View File

@ -13,20 +13,20 @@ import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.security.CryptoException;
public abstract class VulcanJob extends JobService {
public abstract class VulcanService extends JobService {
private SyncTask syncTask = new SyncTask();
@Override
public boolean onStartJob(JobParameters params) {
Log.d(VulcanSync.DEBUG_TAG, "Wulkanowy services start");
Log.d(VulcanJobHelper.DEBUG_TAG, "Wulkanowy services start");
syncTask.execute(params);
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
Log.e(VulcanSync.DEBUG_TAG, "Wulkanowy serives stop");
Log.e(VulcanJobHelper.DEBUG_TAG, "Wulkanowy serives stop");
syncTask.cancel(true);
return true;
}
@ -41,7 +41,7 @@ public abstract class VulcanJob extends JobService {
try {
workToBePerformed();
} catch (Exception e) {
Log.e(VulcanSync.DEBUG_TAG, "User logging in the background failed", e);
Log.e(VulcanJobHelper.DEBUG_TAG, "User logging in the background failed", e);
} finally {
jobFinished(params[0], false);
}

View File

@ -18,7 +18,7 @@ import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.security.Safety;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.jobs.VulcanSync;
import io.github.wulkanowy.services.jobs.VulcanJobHelper;
public class AccountSynchronisation {
@ -31,7 +31,7 @@ public class AccountSynchronisation {
if (userId != 0) {
Log.d(VulcanSync.DEBUG_TAG, "Login current user id=" + String.valueOf(userId));
Log.d(VulcanJobHelper.DEBUG_TAG, "Login current user id=" + String.valueOf(userId));
Safety safety = new Safety();
Account account = accountDao.load(userId);
@ -46,7 +46,7 @@ public class AccountSynchronisation {
.setUserId(userId)
.setVulcan(vulcan);
} else {
Log.wtf(VulcanSync.DEBUG_TAG, "loginCurrentUser - USERID IS EMPTY");
Log.wtf(VulcanJobHelper.DEBUG_TAG, "loginCurrentUser - USERID IS EMPTY");
throw new IOException("Can't find user with index 0");
}
}
@ -70,7 +70,7 @@ public class AccountSynchronisation {
userId = accountDao.insert(account);
Log.d(VulcanSync.DEBUG_TAG, "Login and save new user id=" + String.valueOf(userId));
Log.d(VulcanJobHelper.DEBUG_TAG, "Login and save new user id=" + String.valueOf(userId));
SharedPreferences sharedPreferences = context.getSharedPreferences("LoginData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();

View File

@ -19,7 +19,7 @@ import io.github.wulkanowy.dao.entities.GradeDao;
import io.github.wulkanowy.dao.entities.Subject;
import io.github.wulkanowy.dao.entities.SubjectDao;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.jobs.VulcanSync;
import io.github.wulkanowy.services.jobs.VulcanJobHelper;
import io.github.wulkanowy.utilities.ConversionVulcanObject;
public class GradesSynchronisation {
@ -57,6 +57,6 @@ public class GradesSynchronisation {
gradeDao.insertInTx(lastList);
Log.d(VulcanSync.DEBUG_TAG, "Synchronization grades (amount = " + String.valueOf(lastList.size() + ")"));
Log.d(VulcanJobHelper.DEBUG_TAG, "Synchronization grades (amount = " + String.valueOf(lastList.size() + ")"));
}
}

View File

@ -12,7 +12,7 @@ import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.dao.entities.Subject;
import io.github.wulkanowy.dao.entities.SubjectDao;
import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.jobs.VulcanSync;
import io.github.wulkanowy.services.jobs.VulcanJobHelper;
import io.github.wulkanowy.utilities.ConversionVulcanObject;
public class SubjectsSynchronisation {
@ -36,6 +36,6 @@ public class SubjectsSynchronisation {
subjectDao.insertInTx(preparedList);
Log.d(VulcanSync.DEBUG_TAG, "Synchronization subjects (amount = " + String.valueOf(subjectEntitiesList.size() + ")"));
Log.d(VulcanJobHelper.DEBUG_TAG, "Synchronization subjects (amount = " + String.valueOf(subjectEntitiesList.size() + ")"));
}
}

View File

@ -0,0 +1,53 @@
package io.github.wulkanowy.utilities;
import java.util.List;
import io.github.wulkanowy.dao.entities.Grade;
public abstract class AverageCalculator {
public static float calculate(List<Grade> gradeList) {
float counter = 0f;
float denominator = 0f;
for (Grade grade : gradeList) {
int integerWeight = getIntegerForWeightOfGrade(grade.getWeight());
float floatValue = getMathematicalValueOfGrade(grade.getValue());
if (floatValue != -1f) {
counter += floatValue * integerWeight;
denominator += integerWeight;
}
}
if (counter == 0f) {
return -1f;
} else {
return counter / denominator;
}
}
private static float getMathematicalValueOfGrade(String valueOfGrade) {
if (valueOfGrade.matches("[-|+|=]{0,2}[0-6]") || valueOfGrade.matches("[0-6][-|+|=]{0,2}")) {
if (valueOfGrade.matches("[-][0-6]") || valueOfGrade.matches("[0-6][-]")) {
String replacedValue = valueOfGrade.replaceAll("[-]", "");
return Float.valueOf(replacedValue) - 0.25f;
} else if (valueOfGrade.matches("[+][0-6]") || valueOfGrade.matches("[0-6][+]")) {
String replacedValue = valueOfGrade.replaceAll("[+]", "");
return Float.valueOf((replacedValue)) + 0.25f;
} else if (valueOfGrade.matches("[-|=]{1,2}[0-6]") || valueOfGrade.matches("[0-6][-|=]{1,2}")) {
String replacedValue = valueOfGrade.replaceAll("[-|=]{1,2}", "");
return Float.valueOf((replacedValue)) - 0.5f;
} else {
return Float.valueOf(valueOfGrade);
}
} else {
return -1;
}
}
private static int getIntegerForWeightOfGrade(String weightOfGrade) {
return Integer.valueOf(weightOfGrade.substring(0, weightOfGrade.length() - 3));
}
}

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="35dp"
android:height="35dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#000000"
android:pathData="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" />
<path android:pathData="M0-.75h24v24H0z" />
</vector>

View File

@ -4,5 +4,12 @@
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#ffffff" android:pathData="M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z" />
<path
android:fillColor="#ffffff"
android:pathData="M19.4,13c0-0.3,0.1-0.7,0.1-1s0-0.7-0.1-1l2.1-1.5c0.2-0.1,0.3-0.4,0.1-0.7l-2-3.5C19.5,5,19.2,4.9,19,5l-2.4,1.1
c-0.5-0.4-1.2-0.8-1.8-1l-0.3-2.6C14.5,2.2,14.3,2,14,2H10C9.7,2,9.5,2.2,9.5,2.5L9.2,5c-0.7,0.3-1.3,0.6-1.8,1L5,5
C4.8,4.9,4.5,5,4.4,5.2l-2,3.5C2.2,9,2.2,9.3,2.5,9.4L4.6,11c0,0.3-0.1,0.7-0.1,1s0,0.7,0.1,1l-2.1,1.5c-0.2,0.1-0.3,0.4-0.1,0.7
l2,3.5C4.5,19,4.8,19.1,5,19l2.4-1.1c0.5,0.4,1.2,0.8,1.8,1l0.3,2.6c0,0.3,0.2,0.5,0.5,0.5H14c0.3,0,0.5-0.2,0.5-0.5l0.3-2.6
c0.7-0.3,1.3-0.6,1.8-1L19,19c0.2,0.1,0.5,0,0.6-0.2l2-3.5c0.1-0.2,0.1-0.5-0.1-0.7L19.4,13z M12,16c-2.2,0-4-1.8-4-4
c0-2.2,1.8-4,4-4s4,1.8,4,4C16,14.2,14.2,16,12,16z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/colorPrimary"
android:pathData="M13,13H11V7H13M13,17H11V15H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z" />
</vector>

View File

@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="90"
android:angle="270"
android:centerColor="@android:color/transparent"
android:centerX="0.01"
android:startColor="#60606060" />

View File

@ -9,12 +9,11 @@
android:weightSum="1"
tools:context="io.github.wulkanowy.activity.dashboard.DashboardActivity">
<FrameLayout
<android.support.design.widget.CoordinatorLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fitsSystemWindows="true"
app:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior" />

View File

@ -1,13 +1,19 @@
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator_grade"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="io.github.wulkanowy.activity.dashboard.grades.GradesFragment">
<android.support.v7.widget.RecyclerView
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/grade_swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/subject_grade_recycler" />
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/subject_grade_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout
android:id="@+id/loadingPanel"
@ -21,4 +27,6 @@
android:indeterminate="true" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,4 +1,5 @@
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/grade_cardview"
android:layout_width="match_parent"
@ -23,27 +24,28 @@
<TextView
android:id="@+id/grade_text"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_centerVertical="true"
android:gravity="center"
android:textSize="19sp" />
android:maxLength="5"
android:textSize="16sp" />
<TextView
android:id="@+id/description_grade_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginEnd="10dp"
android:layout_marginEnd="40dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginRight="40dp"
android:layout_marginStart="10dp"
android:layout_toEndOf="@+id/grade_text"
android:layout_toRightOf="@+id/grade_text"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/app_name"
android:textSize="19sp" />
android:textSize="15sp" />
<TextView
android:id="@+id/grade_date_text"
@ -53,7 +55,16 @@
android:layout_alignLeft="@+id/description_grade_text"
android:layout_alignStart="@+id/description_grade_text"
android:text="@string/grades_text"
android:textSize="13sp" />
android:textSize="12sp" />
<ImageView
android:id="@+id/grade_new_grades_alert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginTop="10dp"
app:srcCompat="@drawable/subject_alert_circle" />
</RelativeLayout>
</android.support.v7.widget.CardView>

View File

@ -179,6 +179,7 @@
android:layout_marginRight="10dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:text="@string/ok_text"
android:textSize="16sp" />

View File

@ -2,36 +2,51 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/border"
android:foreground="?attr/selectableItemBackgroundBorderless">
android:background="@drawable/subject_border_1px"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:padding="15dp">
<TextView
android:id="@+id/subject_text"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:layout_marginRight="50dp"
android:layout_marginEnd="50dp"
android:layout_marginEnd="35dp"
android:layout_marginRight="35dp"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/app_name"
android:textSize="19sp" />
android:textSize="17sp" />
<TextView
android:id="@+id/subject_grades_average"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/subject_text"
android:layout_marginTop="5dp"
android:text="@string/app_name"
android:textColor="#4C4C4C"
android:textSize="12sp" />
<TextView
android:id="@+id/subject_number_of_grades"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/subject_text"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:layout_toEndOf="@+id/subject_grades_average"
android:layout_toRightOf="@+id/subject_grades_average"
android:text="@string/app_name"
android:textColor="#4C4C4C"
android:textSize="12sp" />
<ImageView
android:id="@+id/group_indicator_down"
android:id="@+id/subject_new_grades_alert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_arrow_down" />
<ImageView
android:id="@+id/group_indicator_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:rotation="180"
app:srcCompat="@drawable/ic_arrow_down" />
android:layout_marginTop="10dp"
app:srcCompat="@drawable/subject_alert_circle" />
</RelativeLayout>

View File

@ -20,11 +20,8 @@
<string name="lessonplan_text">Plan lekcji</string>
<string name="settings_text">Ustawienia</string>
<string name="noInternet_text">Brak połączenia z internetem</string>
<string name="login_cookies_save_failed_text">Nie udało się zapisać sesji</string>
<string name="SQLite_ioError_text">W bazie danych wystąpił błąd. Zrestartuj aplikacje a także sprawdź iość wolnego miejsca w pamięci wewnętrznej</string>
<string name="root_failed_text">To urządzenie posiada posiada podwyższone uprawnienia (root). Automatyczne logowanie zosatło wyłączone.</string>
<string name="encrypt_failed_text">Szyfrowanie nie powiodło się. Automatyczne logowanie zostało wyłączone</string>
<string name="decrypt_failed_text">Deszyfrowanie nie powiodło się. Automatyczne logowanie zostało wyłączone</string>
<string name="version_text">Wersja\u0020</string>
<string name="dialog_description_text">Opis</string>
<string name="dialog_weight_text">Waga</string>
@ -38,5 +35,16 @@
<string name="color_green_text">Zielony</string>
<string name="noColor_text">Brak koloru</string>
<string name="ok_text">OK</string>
<string name="dialog_subject_text">Przedmiot</string>
<string name="refresh_error_text">"Podczas odświeżania zawartości wystąpił błąd. "</string>
<string name="snackbar_no_grades">Brak nowych ocen</string>
<string name="snackbar_new_grade">Ilość nowych ocen: %1$d</string>
<plurals name="numberOfGrades">
<item quantity="one">%d ocena</item>
<item quantity="few">%d oceny</item>
<item quantity="many">%d ocen</item>
<item quantity="other">%d ocen</item>
</plurals>
<string name="info_average_grades">Średnia: %1$.2f</string>
<string name="info_no_average">Brak średniej</string>
</resources>

View File

@ -20,11 +20,8 @@
<string name="lessonplan_text">Lesson Plan</string>
<string name="settings_text">Settings</string>
<string name="noInternet_text">No internet connection</string>
<string name="login_cookies_save_failed_text">Failed to save session</string>
<string name="SQLite_ioError_text">An error occurred in the database. Restart the applications and check the free space in the internal memory</string>
<string name="root_failed_text">This device is rooted. Automatic login has been disabled</string>
<string name="encrypt_failed_text">Encryption failed. Automatic login has been disabled</string>
<string name="decrypt_failed_text">Decrypt is failed. Automatic login has been disable</string>
<string name="version_text">Version\u0020</string>
<string name="dialog_description_text">Description</string>
<string name="dialog_weight_text">Weight</string>
@ -38,5 +35,14 @@
<string name="color_green_text">Green</string>
<string name="noColor_text">No color</string>
<string name="ok_text">OK</string>
<string name="dialog_subject_text">Subject</string>
<string name="refresh_error_text">An error occurred while refreshing the content.</string>
<string name="snackbar_no_grades">No new grades</string>
<string name="snackbar_new_grade">Number of new grades: %1$d</string>
<plurals name="numberOfGrades">
<item quantity="one">%d grade</item>
<item quantity="other">%d grades</item>
</plurals>
<string name="info_average_grades">Average: %1$.2f</string>
<string name="info_no_average">No average</string>
</resources>

View File

@ -0,0 +1,42 @@
package io.github.wulkanowy.utilities;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import io.github.wulkanowy.dao.entities.Grade;
public class AverageCalculatorTest extends AverageCalculator {
@Test
public void averageTest() {
List<Grade> gradeList = new ArrayList<>();
gradeList.add(new Grade().setValue("np.").setWeight("1,00"));
gradeList.add(new Grade().setValue("-5").setWeight("10,00"));
gradeList.add(new Grade().setValue("--5").setWeight("10,00"));
gradeList.add(new Grade().setValue("=5").setWeight("10,00"));
gradeList.add(new Grade().setValue("+5").setWeight("10,00"));
gradeList.add(new Grade().setValue("5").setWeight("10,00"));
List<Grade> gradeList1 = new ArrayList<>();
gradeList1.add(new Grade().setValue("np.").setWeight("1,00"));
gradeList1.add(new Grade().setValue("5-").setWeight("10,00"));
gradeList1.add(new Grade().setValue("5--").setWeight("10,00"));
gradeList1.add(new Grade().setValue("5=").setWeight("10,00"));
gradeList1.add(new Grade().setValue("5+").setWeight("10,00"));
gradeList1.add(new Grade().setValue("5").setWeight("10,00"));
Assert.assertEquals(4.8f, AverageCalculator.calculate(gradeList), 0.0f);
Assert.assertEquals(4.8f, AverageCalculator.calculate(gradeList1), 0.0f);
}
@Test
public void errorAverageTest() {
List<Grade> gradeList = new ArrayList<>();
gradeList.add(new Grade().setValue("np.").setWeight("1,00"));
Assert.assertEquals(-1f, AverageCalculator.calculate(gradeList), 0.0f);
}
}

View File

@ -8,7 +8,7 @@ buildscript {
maven { url 'https://maven.google.com' }
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
// NOTE: Do not place your application dependencies here; they belong

View File

@ -1,6 +1,6 @@
#Wed Mar 08 19:17:31 CET 2017
#Thu Oct 26 14:47:13 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip