diff --git a/app/build.gradle b/app/build.gradle index 8f0c1429f..1513508b9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/src/androidTest/java/io/github/wulkanowy/dao/DatabaseAccessTest.java b/app/src/androidTest/java/io/github/wulkanowy/dao/DatabaseAccessTest.java new file mode 100644 index 000000000..570526ee9 --- /dev/null +++ b/app/src/androidTest/java/io/github/wulkanowy/dao/DatabaseAccessTest.java @@ -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(); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 244a06b1d..15c4d7893 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -40,7 +40,7 @@ android:label="@string/activity_dashboard_text" /> diff --git a/app/src/main/java/io/github/wulkanowy/activity/dashboard/grades/GradesAdapter.java b/app/src/main/java/io/github/wulkanowy/activity/dashboard/grades/GradesAdapter.java index 9a4ca82f6..9b62c1e52 100644 --- a/app/src/main/java/io/github/wulkanowy/activity/dashboard/grades/GradesAdapter.java +++ b/app/src/main/java/io/github/wulkanowy/activity/dashboard/grades/GradesAdapter.java @@ -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 { private Activity activity; - public GradesAdapter(List groups, Context context) { + private int numberOfNotReadGrade; + + public GradesAdapter(List groups, Activity activity) { super(groups); - activity = (Activity) context; + this.activity = activity; } @Override @@ -59,80 +57,42 @@ public class GradesAdapter extends ExpandableRecyclerViewAdapter 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 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 { + private void prepareSubjectsWithGradesList(DaoSession daoSession) { + subjectWithGradesList = new ArrayList<>(); - private DaoSession daoSession; + long userId = getContext().getSharedPreferences("LoginData", Context.MODE_PRIVATE) + .getLong("userId", 0); - GradesTask(DaoSession daoSession) { - this.daoSession = daoSession; + AccountDao accountDao = daoSession.getAccountDao(); + Account account = accountDao.load(userId); + + for (Subject subject : account.getSubjectList()) { + List gradeList = subject.getGradeList(); + if (gradeList.size() != 0) { + SubjectWithGrades subjectWithGrades = new SubjectWithGrades(subject.getName(), gradeList); + subjectWithGradesList.add(subjectWithGrades); + } } + } + + private class GradesTask extends AsyncTask { @Override - protected Void doInBackground(Void... params) { - - long userId = getActivity().getSharedPreferences("LoginData", Context.MODE_PRIVATE) - .getLong("userId", 0); - - AccountDao accountDao = daoSession.getAccountDao(); - Account account = accountDao.load(userId); - - for (Subject subject : account.getSubjectList()) { - List gradeList = subject.getGradeList(); - if (gradeList.size() != 0) { - SubjectWithGrades subjectWithGrades = new SubjectWithGrades(subject.getName(), gradeList); - subjectWithGradesList.add(subjectWithGrades); - } - } + 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 { + + @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); + } + } + } } diff --git a/app/src/main/java/io/github/wulkanowy/activity/main/LoginTask.java b/app/src/main/java/io/github/wulkanowy/activity/main/LoginTask.java index a5295daaa..c1cc0458a 100644 --- a/app/src/main/java/io/github/wulkanowy/activity/main/LoginTask.java +++ b/app/src/main/java/io/github/wulkanowy/activity/main/LoginTask.java @@ -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 { @@ -74,7 +74,7 @@ public class LoginTask extends AsyncTask { protected void onPostExecute(Integer messageID) { super.onPostExecute(messageID); - GradesSync gradesSync = new GradesSync(); + GradeJob gradesSync = new GradeJob(); gradesSync.scheduledJob(activity); progress.dismiss(); diff --git a/app/src/main/java/io/github/wulkanowy/activity/started/LoadingTask.java b/app/src/main/java/io/github/wulkanowy/activity/started/LoadingTask.java index 7ca8b59ea..bdf0ee96f 100644 --- a/app/src/main/java/io/github/wulkanowy/activity/started/LoadingTask.java +++ b/app/src/main/java/io/github/wulkanowy/activity/started/LoadingTask.java @@ -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 { @@ -42,7 +42,7 @@ public class LoadingTask extends AsyncTask { 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); diff --git a/app/src/main/java/io/github/wulkanowy/dao/DatabaseAccess.java b/app/src/main/java/io/github/wulkanowy/dao/DatabaseAccess.java new file mode 100644 index 000000000..0a18bd81d --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/dao/DatabaseAccess.java @@ -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 getNewGrades(DaoSession daoSession) { + Query gradeQuery = daoSession.getGradeDao().queryBuilder() + .where(GradeDao.Properties.IsNew.eq(1)) + .build(); + + return gradeQuery.list(); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/dao/EntitiesCompare.java b/app/src/main/java/io/github/wulkanowy/dao/EntitiesCompare.java index c79b11450..48b180ad9 100644 --- a/app/src/main/java/io/github/wulkanowy/dao/EntitiesCompare.java +++ b/app/src/main/java/io/github/wulkanowy/dao/EntitiesCompare.java @@ -15,12 +15,24 @@ public abstract class EntitiesCompare { .removeAll(newList, oldList)); List updatedList = new ArrayList<>(CollectionUtils .removeAll(newList, addedOrUpdatedGradeList)); + List 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; } } diff --git a/app/src/main/java/io/github/wulkanowy/dao/entities/Grade.java b/app/src/main/java/io/github/wulkanowy/dao/entities/Grade.java index 759c66003..60100053e 100644 --- a/app/src/main/java/io/github/wulkanowy/dao/entities/Grade.java +++ b/app/src/main/java/io/github/wulkanowy/dao/entities/Grade.java @@ -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 CREATOR = new Creator() { @@ -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; } } diff --git a/app/src/main/java/io/github/wulkanowy/services/LoginSession.java b/app/src/main/java/io/github/wulkanowy/services/LoginSession.java index 57f69a3be..f5f12c423 100644 --- a/app/src/main/java/io/github/wulkanowy/services/LoginSession.java +++ b/app/src/main/java/io/github/wulkanowy/services/LoginSession.java @@ -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(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/services/VulcanSynchronization.java b/app/src/main/java/io/github/wulkanowy/services/VulcanSynchronization.java index b058e57db..d4a76f23a 100644 --- a/app/src/main/java/io/github/wulkanowy/services/VulcanSynchronization.java +++ b/app/src/main/java/io/github/wulkanowy/services/VulcanSynchronization.java @@ -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; } } diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/GradesSync.java b/app/src/main/java/io/github/wulkanowy/services/jobs/GradeJob.java similarity index 93% rename from app/src/main/java/io/github/wulkanowy/services/jobs/GradesSync.java rename to app/src/main/java/io/github/wulkanowy/services/jobs/GradeJob.java index 1410fbf3b..ed1d90cf7 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/GradesSync.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/GradeJob.java @@ -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, diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/SubjectsSync.java b/app/src/main/java/io/github/wulkanowy/services/jobs/SubjectJob.java similarity index 93% rename from app/src/main/java/io/github/wulkanowy/services/jobs/SubjectsSync.java rename to app/src/main/java/io/github/wulkanowy/services/jobs/SubjectJob.java index dc91e2459..810f0d2ec 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/SubjectsSync.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/SubjectJob.java @@ -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, diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/VulcanSync.java b/app/src/main/java/io/github/wulkanowy/services/jobs/VulcanJobHelper.java similarity index 93% rename from app/src/main/java/io/github/wulkanowy/services/jobs/VulcanSync.java rename to app/src/main/java/io/github/wulkanowy/services/jobs/VulcanJobHelper.java index 8ff1d4854..7d55f7998 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/VulcanSync.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/VulcanJobHelper.java @@ -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"; diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/VulcanJob.java b/app/src/main/java/io/github/wulkanowy/services/jobs/VulcanService.java similarity index 82% rename from app/src/main/java/io/github/wulkanowy/services/jobs/VulcanJob.java rename to app/src/main/java/io/github/wulkanowy/services/jobs/VulcanService.java index 54da4214a..e85a2217d 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/VulcanJob.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/VulcanService.java @@ -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); } diff --git a/app/src/main/java/io/github/wulkanowy/services/synchronisation/AccountSynchronisation.java b/app/src/main/java/io/github/wulkanowy/services/synchronisation/AccountSynchronisation.java index 04cd98024..c4393d577 100644 --- a/app/src/main/java/io/github/wulkanowy/services/synchronisation/AccountSynchronisation.java +++ b/app/src/main/java/io/github/wulkanowy/services/synchronisation/AccountSynchronisation.java @@ -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(); diff --git a/app/src/main/java/io/github/wulkanowy/services/synchronisation/GradesSynchronisation.java b/app/src/main/java/io/github/wulkanowy/services/synchronisation/GradesSynchronisation.java index 4f56cebeb..9dc399038 100644 --- a/app/src/main/java/io/github/wulkanowy/services/synchronisation/GradesSynchronisation.java +++ b/app/src/main/java/io/github/wulkanowy/services/synchronisation/GradesSynchronisation.java @@ -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() + ")")); } } diff --git a/app/src/main/java/io/github/wulkanowy/services/synchronisation/SubjectsSynchronisation.java b/app/src/main/java/io/github/wulkanowy/services/synchronisation/SubjectsSynchronisation.java index 7cb9b505e..38f604a1b 100644 --- a/app/src/main/java/io/github/wulkanowy/services/synchronisation/SubjectsSynchronisation.java +++ b/app/src/main/java/io/github/wulkanowy/services/synchronisation/SubjectsSynchronisation.java @@ -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() + ")")); } } diff --git a/app/src/main/java/io/github/wulkanowy/services/synchronisation/VulcanSynchronisation.java b/app/src/main/java/io/github/wulkanowy/services/synchronisation/VulcanSynchronisation.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/src/main/java/io/github/wulkanowy/utilities/AverageCalculator.java b/app/src/main/java/io/github/wulkanowy/utilities/AverageCalculator.java new file mode 100644 index 000000000..0eb590a98 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utilities/AverageCalculator.java @@ -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 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)); + } +} diff --git a/app/src/main/res/drawable/ic_arrow_down.xml b/app/src/main/res/drawable/ic_arrow_down.xml deleted file mode 100644 index 9ed8d571b..000000000 --- a/app/src/main/res/drawable/ic_arrow_down.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/icon_other_24dp.xml b/app/src/main/res/drawable/icon_other_24dp.xml index 680f5abca..67173d907 100644 --- a/app/src/main/res/drawable/icon_other_24dp.xml +++ b/app/src/main/res/drawable/icon_other_24dp.xml @@ -4,5 +4,12 @@ android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/subject_alert_circle.xml b/app/src/main/res/drawable/subject_alert_circle.xml new file mode 100644 index 000000000..92f7cd3be --- /dev/null +++ b/app/src/main/res/drawable/subject_alert_circle.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/border.xml b/app/src/main/res/drawable/subject_border_1px.xml similarity index 91% rename from app/src/main/res/drawable/border.xml rename to app/src/main/res/drawable/subject_border_1px.xml index a1ce73317..dc33b8aa2 100644 --- a/app/src/main/res/drawable/border.xml +++ b/app/src/main/res/drawable/subject_border_1px.xml @@ -2,7 +2,7 @@ diff --git a/app/src/main/res/layout/activity_dashboard.xml b/app/src/main/res/layout/activity_dashboard.xml index 4bd03cfee..a5988d032 100644 --- a/app/src/main/res/layout/activity_dashboard.xml +++ b/app/src/main/res/layout/activity_dashboard.xml @@ -9,12 +9,11 @@ android:weightSum="1" tools:context="io.github.wulkanowy.activity.dashboard.DashboardActivity"> - diff --git a/app/src/main/res/layout/fragment_grades.xml b/app/src/main/res/layout/fragment_grades.xml index c1686bd28..92d81f686 100644 --- a/app/src/main/res/layout/fragment_grades.xml +++ b/app/src/main/res/layout/fragment_grades.xml @@ -1,24 +1,32 @@ - + android:layout_height="match_parent"> - + - - + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/grade_item.xml b/app/src/main/res/layout/grade_item.xml index f7364bb65..2a4c134ba 100644 --- a/app/src/main/res/layout/grade_item.xml +++ b/app/src/main/res/layout/grade_item.xml @@ -1,4 +1,5 @@ + android:maxLength="5" + android:textSize="16sp" /> + android:textSize="15sp" /> + android:textSize="12sp" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/grades_dialog.xml b/app/src/main/res/layout/grades_dialog.xml index 6b5d1e9ec..68aa48d3f 100644 --- a/app/src/main/res/layout/grades_dialog.xml +++ b/app/src/main/res/layout/grades_dialog.xml @@ -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" /> diff --git a/app/src/main/res/layout/subject_item.xml b/app/src/main/res/layout/subject_item.xml index e151079d3..5ba243e59 100644 --- a/app/src/main/res/layout/subject_item.xml +++ b/app/src/main/res/layout/subject_item.xml @@ -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"> + android:textSize="17sp" /> + + + + - - - + android:layout_marginTop="10dp" + app:srcCompat="@drawable/subject_alert_circle" /> \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index cddf74afa..c9c6ef138 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -20,11 +20,8 @@ Plan lekcji Ustawienia Brak połączenia z internetem - Nie udało się zapisać sesji - W bazie danych wystąpił błąd. Zrestartuj aplikacje a także sprawdź iość wolnego miejsca w pamięci wewnętrznej To urządzenie posiada posiada podwyższone uprawnienia (root). Automatyczne logowanie zosatło wyłączone. Szyfrowanie nie powiodło się. Automatyczne logowanie zostało wyłączone - Deszyfrowanie nie powiodło się. Automatyczne logowanie zostało wyłączone Wersja\u0020 Opis Waga @@ -38,5 +35,16 @@ Zielony Brak koloru OK - Przedmiot + "Podczas odświeżania zawartości wystąpił błąd. " + Brak nowych ocen + Ilość nowych ocen: %1$d + + + %d ocena + %d oceny + %d ocen + %d ocen + + Średnia: %1$.2f + Brak średniej diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7b16d9f83..a064518a6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,11 +20,8 @@ Lesson Plan Settings No internet connection - Failed to save session - An error occurred in the database. Restart the applications and check the free space in the internal memory This device is rooted. Automatic login has been disabled Encryption failed. Automatic login has been disabled - Decrypt is failed. Automatic login has been disable Version\u0020 Description Weight @@ -38,5 +35,14 @@ Green No color OK - Subject + An error occurred while refreshing the content. + No new grades + Number of new grades: %1$d + + + %d grade + %d grades + + Average: %1$.2f + No average diff --git a/app/src/test/java/io/github/wulkanowy/utilities/AverageCalculatorTest.java b/app/src/test/java/io/github/wulkanowy/utilities/AverageCalculatorTest.java new file mode 100644 index 000000000..c40a8149c --- /dev/null +++ b/app/src/test/java/io/github/wulkanowy/utilities/AverageCalculatorTest.java @@ -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 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 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 gradeList = new ArrayList<>(); + gradeList.add(new Grade().setValue("np.").setWeight("1,00")); + + Assert.assertEquals(-1f, AverageCalculator.calculate(gradeList), 0.0f); + } +} diff --git a/build.gradle b/build.gradle index ef951a0d4..2f4cb6041 100644 --- a/build.gradle +++ b/build.gradle @@ -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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1c74e589e..01785fbfc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -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