1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-09-20 02:29:08 -05:00

Refactorization of the app (#31)

* Refactor LoadingTask
* Remove LoadingTask class
* Fix context leak in LoginTask
* Refactorisation GradesFragment
* Refactorization synchronization
* Fix leak in VulcanService
* Update mockito
* Add more tests for EntitiesCompare
* Fix Instant Run
* Add margin to grades
* Update ci android image
This commit is contained in:
Rafał Borcz 2017-11-06 17:25:38 +01:00 committed by Mikołaj Pich
parent 54112f73f1
commit e5ea6e0b41
32 changed files with 374 additions and 284 deletions

View File

@ -7,7 +7,7 @@ references:
container_config: &container_config container_config: &container_config
docker: docker:
- image: circleci/android:api-26-alpha - image: circleci/android:api-27-alpha
working_directory: *workspace_root working_directory: *workspace_root
environment: environment:
environment: environment:

View File

@ -1,4 +1,4 @@
image: circleci/android:api-25-alpha image: circleci/android:api-27-alpha
before_script: before_script:
- export GRADLE_USER_HOME=`pwd`/.gradle - export GRADLE_USER_HOME=`pwd`/.gradle

View File

@ -62,10 +62,10 @@ dependencies {
debugCompile 'com.amitshekhar.android:debug-db:1.0.1' debugCompile 'com.amitshekhar.android:debug-db:1.0.1'
debugCompile 'net.zetetic:android-database-sqlcipher:3.5.7@aar' debugCompile 'net.zetetic:android-database-sqlcipher:3.5.7@aar'
androidTestCompile 'org.mockito:mockito-android:2.10.0' androidTestCompile 'org.mockito:mockito-android:2.11.0'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.10.0' testCompile 'org.mockito:mockito-core:2.11.0'
androidTestCompile('com.android.support.test.espresso:espresso-core:3.0.1', { androidTestCompile('com.android.support.test.espresso:espresso-core:3.0.1', {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'

View File

@ -27,10 +27,10 @@ import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException; import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.security.Safety; import io.github.wulkanowy.security.Safety;
import io.github.wulkanowy.services.LoginSession; import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.synchronisation.AccountAuthorization; import io.github.wulkanowy.services.synchronisation.CurrentAccountLogin;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class AccountAuthorizationTest { public class CurrentAccountLoginTest {
private static DaoSession daoSession; private static DaoSession daoSession;
@ -62,8 +62,8 @@ public class AccountAuthorizationTest {
public void emptyUserIdTest() throws CryptoException, BadCredentialsException, public void emptyUserIdTest() throws CryptoException, BadCredentialsException,
AccountPermissionException, IOException, LoginErrorException { AccountPermissionException, IOException, LoginErrorException {
AccountAuthorization accountAuthorization = new AccountAuthorization(context, daoSession, new Vulcan()); CurrentAccountLogin currentAccountLogin = new CurrentAccountLogin(context, daoSession, new Vulcan());
accountAuthorization.loginCurrentUser(); currentAccountLogin.loginCurrentUser();
} }
@Test @Test
@ -82,8 +82,8 @@ public class AccountAuthorizationTest {
Vulcan vulcan = Mockito.mock(Vulcan.class); Vulcan vulcan = Mockito.mock(Vulcan.class);
Mockito.doNothing().when(vulcan).login("TEST@TEST", "TEST", "TEST_SYMBOL", "TEST_ID"); Mockito.doNothing().when(vulcan).login("TEST@TEST", "TEST", "TEST_SYMBOL", "TEST_ID");
AccountAuthorization accountAuthorization = new AccountAuthorization(targetContext, daoSession, vulcan); CurrentAccountLogin currentAccountLogin = new CurrentAccountLogin(targetContext, daoSession, vulcan);
LoginSession loginSession = accountAuthorization.loginCurrentUser(); LoginSession loginSession = currentAccountLogin.loginCurrentUser();
Assert.assertNotNull(loginSession); Assert.assertNotNull(loginSession);
Assert.assertEquals(loginSession.getUserId(), userId); Assert.assertEquals(loginSession.getUserId(), userId);

View File

@ -22,9 +22,9 @@ import io.github.wulkanowy.dao.entities.DaoMaster;
import io.github.wulkanowy.dao.entities.DaoSession; import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.Safety; import io.github.wulkanowy.security.Safety;
import io.github.wulkanowy.services.LoginSession; import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.synchronisation.AccountRegistration; import io.github.wulkanowy.services.synchronisation.FirstAccountLogin;
public class AccountRegistrationTest { public class FirstAccountLoginTest {
private static DaoSession daoSession; private static DaoSession daoSession;
@ -55,9 +55,9 @@ public class AccountRegistrationTest {
Login login = Mockito.mock(Login.class); Login login = Mockito.mock(Login.class);
Mockito.when(login.sendCredentials(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) Mockito.when(login.sendCredentials(Mockito.anyString(), Mockito.anyString(), Mockito.anyString()))
.thenReturn(certificate); .thenReturn(certificate);
AccountRegistration accountRegistration = new AccountRegistration(login, new Vulcan(), "TEST@TEST", "TEST_PASS", "TEST_SYMBOL"); FirstAccountLogin firstAccountLogin = new FirstAccountLogin(login, new Vulcan(), "TEST@TEST", "TEST_PASS", "TEST_SYMBOL");
Assert.assertEquals(certificate, accountRegistration.connect()); Assert.assertEquals(certificate, firstAccountLogin.connect());
} }
@Test @Test
@ -79,8 +79,8 @@ public class AccountRegistrationTest {
Login login = Mockito.mock(Login.class); Login login = Mockito.mock(Login.class);
Mockito.when(login.sendCertificate(Mockito.anyString(), Mockito.anyString())).thenReturn("TEST-SYMBOL"); Mockito.when(login.sendCertificate(Mockito.anyString(), Mockito.anyString())).thenReturn("TEST-SYMBOL");
AccountRegistration accountRegistration = new AccountRegistration(login, vulcan, "TEST@TEST", "TEST-PASS", "default"); FirstAccountLogin firstAccountLogin = new FirstAccountLogin(login, vulcan, "TEST@TEST", "TEST-PASS", "default");
LoginSession loginSession = accountRegistration.login(targetContext, daoSession, "<xml>cert</xml>"); LoginSession loginSession = firstAccountLogin.login(targetContext, daoSession, "<xml>cert</xml>");
Long userId = targetContext.getSharedPreferences("LoginData", Context.MODE_PRIVATE).getLong("userId", 0); Long userId = targetContext.getSharedPreferences("LoginData", Context.MODE_PRIVATE).getLong("userId", 0);

View File

@ -47,7 +47,7 @@ public class GradeSynchronizationTest {
} }
@Test @Test
public void syncGradesEmptyBaseTest() throws Exception { public void syncGradesEmptyDatabaseTest() throws Exception {
Long userId = daoSession.getAccountDao().insert(new Account().setEmail("TEST@TEST")); Long userId = daoSession.getAccountDao().insert(new Account().setEmail("TEST@TEST"));
Long subjectId = daoSession.getSubjectDao().insert(new Subject().setName("Matematyka").setUserId(userId)); Long subjectId = daoSession.getSubjectDao().insert(new Subject().setName("Matematyka").setUserId(userId));
@ -75,7 +75,7 @@ public class GradeSynchronizationTest {
Assert.assertEquals(subjectId, grade.getSubjectId()); Assert.assertEquals(subjectId, grade.getSubjectId());
Assert.assertEquals("Matematyka", grade.getSubject()); Assert.assertEquals("Matematyka", grade.getSubject());
Assert.assertEquals("5", grade.getValue()); Assert.assertEquals("5", grade.getValue());
Assert.assertTrue(grade.getIsNew()); Assert.assertFalse(grade.getIsNew());
} }
@AfterClass @AfterClass

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.activity.dashboard;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView; import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem; import android.view.MenuItem;
@ -15,6 +16,8 @@ import io.github.wulkanowy.activity.dashboard.lessonplan.LessonPlanFragment;
public class DashboardActivity extends AppCompatActivity { public class DashboardActivity extends AppCompatActivity {
private Fragment currentFragment;
private GradesFragment gradesFragment = new GradesFragment(); private GradesFragment gradesFragment = new GradesFragment();
private AttendanceFragment attendanceFragment = new AttendanceFragment(); private AttendanceFragment attendanceFragment = new AttendanceFragment();
@ -28,36 +31,33 @@ public class DashboardActivity extends AppCompatActivity {
@Override @Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) { public boolean onNavigationItemSelected(@NonNull MenuItem item) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.navigation_marks: case R.id.navigation_marks:
setTitle(R.string.grades_text); setTitle(R.string.grades_text);
transaction.replace(R.id.fragment_container, gradesFragment); currentFragment = gradesFragment;
transaction.commit(); break;
return true;
case R.id.navigation_attendance: case R.id.navigation_attendance:
setTitle(R.string.attendance_text); setTitle(R.string.attendance_text);
transaction.replace(R.id.fragment_container, attendanceFragment); currentFragment = attendanceFragment;
transaction.commit(); break;
return true;
case R.id.navigation_lessonplan: case R.id.navigation_lessonplan:
setTitle(R.string.lessonplan_text); setTitle(R.string.lessonplan_text);
transaction.replace(R.id.fragment_container, lessonPlanFragment); currentFragment = lessonPlanFragment;
transaction.commit(); break;
return true;
case R.id.navigation_dashboard: case R.id.navigation_dashboard:
default: default:
setTitle(R.string.dashboard_text); setTitle(R.string.dashboard_text);
transaction.replace(R.id.fragment_container, boardFragment); currentFragment = boardFragment;
break;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, currentFragment);
transaction.commit(); transaction.commit();
return true; return true;
} }
}
}; };
@Override @Override
@ -65,14 +65,27 @@ public class DashboardActivity extends AppCompatActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard); setContentView(R.layout.activity_dashboard);
setTitle(R.string.dashboard_text);
BottomNavigationView navigation = findViewById(R.id.navigation); BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setSelectedItemId(R.id.navigation_dashboard); navigation.setSelectedItemId(R.id.navigation_dashboard);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener); navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
if (savedInstanceState != null) {
currentFragment = getSupportFragmentManager().getFragment(savedInstanceState, "currentFragment");
setTitle(savedInstanceState.getString("activityTitle"));
} else {
currentFragment = boardFragment;
setTitle(R.string.dashboard_text);
}
getSupportFragmentManager().beginTransaction() getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, boardFragment).commit(); .replace(R.id.fragment_container, currentFragment).commit();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("activityTitle", getTitle().toString());
getSupportFragmentManager().putFragment(outState, "currentFragment", currentFragment);
} }
public void onBackPressed() { public void onBackPressed() {

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.activity.dashboard.attendance; package io.github.wulkanowy.activity.dashboard.attendance;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -11,7 +12,7 @@ import io.github.wulkanowy.R;
public class AttendanceFragment extends Fragment { public class AttendanceFragment extends Fragment {
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_attendance, container, false); return inflater.inflate(R.layout.fragment_attendance, container, false);
} }

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.activity.dashboard.board; package io.github.wulkanowy.activity.dashboard.board;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -11,7 +12,7 @@ import io.github.wulkanowy.R;
public class BoardFragment extends Fragment { public class BoardFragment extends Fragment {
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_board, container, false); return inflater.inflate(R.layout.fragment_board, container, false);
} }

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.activity.dashboard.grades; package io.github.wulkanowy.activity.dashboard.grades;
import android.app.Dialog;
import android.app.DialogFragment; import android.app.DialogFragment;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -20,6 +21,10 @@ public class GradesDialogFragment extends DialogFragment {
return new GradesDialogFragment().setGrade(grade); return new GradesDialogFragment().setGrade(grade);
} }
public GradesDialogFragment() {
setRetainInstance(true);
}
public GradesDialogFragment setGrade(Grade grade) { public GradesDialogFragment setGrade(Grade grade) {
this.grade = grade; this.grade = grade;
return this; return this;
@ -50,7 +55,7 @@ public class GradesDialogFragment extends DialogFragment {
descriptionText.setText(grade.getSymbol()); descriptionText.setText(grade.getSymbol());
} }
} else if (!"".equals(grade.getSymbol())) { } else if (!"".equals(grade.getSymbol())) {
descriptionText.setText(grade.getSymbol() + " - " + grade.getDescription()); descriptionText.setText(String.format("%1$s - %2$s", grade.getSymbol(), grade.getDescription()));
} else { } else {
descriptionText.setText(grade.getDescription()); descriptionText.setText(grade.getDescription());
} }
@ -69,6 +74,16 @@ public class GradesDialogFragment extends DialogFragment {
return view; return view;
} }
@Override
public void onDestroyView() {
Dialog dialog = getDialog();
if (dialog != null && getRetainInstance()) {
dialog.setDismissMessage(null);
}
super.onDestroyView();
}
public static int colorHexToColorName(String hexColor) { public static int colorHexToColorName(String hexColor) {
switch (hexColor) { switch (hexColor) {
case "000000": { case "000000": {

View File

@ -1,8 +1,10 @@
package io.github.wulkanowy.activity.dashboard.grades; package io.github.wulkanowy.activity.dashboard.grades;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout; import android.support.v4.widget.SwipeRefreshLayout;
@ -14,6 +16,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Toast; import android.widget.Toast;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -33,20 +36,39 @@ import io.github.wulkanowy.utilities.ConnectionUtilities;
public class GradesFragment extends Fragment { public class GradesFragment extends Fragment {
private List<SubjectWithGrades> subjectWithGradesList = new ArrayList<>(); private static List<SubjectWithGrades> subjectWithGradesList = new ArrayList<>();
private SwipeRefreshLayout swipeRefreshLayout; private static long userId;
private View view;
private RefreshTask refreshTask;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_grades, container, false); DaoSession daoSession;
View view = inflater.inflate(R.layout.fragment_grades, container, false);
if (getActivity() != null) {
daoSession = ((WulkanowyApp) getActivity().getApplication()).getDaoSession();
userId = getActivity().getSharedPreferences("LoginData", Context.MODE_PRIVATE)
.getLong("userId", 0);
prepareRefreshLayout(view, daoSession);
if (subjectWithGradesList.equals(new ArrayList<>())) {
createExpList(view, getActivity());
new GenerateListTask(getActivity(), view, daoSession).execute();
} else {
createExpList(view, getActivity());
view.findViewById(R.id.loadingPanel).setVisibility(View.INVISIBLE);
}
}
return view;
}
private void prepareRefreshLayout(final View mainView, final DaoSession daoSession) {
final SwipeRefreshLayout swipeRefreshLayout = mainView.findViewById(R.id.grade_swipe_refresh);
swipeRefreshLayout = view.findViewById(R.id.grade_swipe_refresh);
swipeRefreshLayout.setColorSchemeResources(android.R.color.black, swipeRefreshLayout.setColorSchemeResources(android.R.color.black,
android.R.color.holo_blue_bright, android.R.color.holo_blue_bright,
android.R.color.holo_green_light, android.R.color.holo_green_light,
@ -56,47 +78,27 @@ public class GradesFragment extends Fragment {
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override @Override
public void onRefresh() { public void onRefresh() {
if (!ConnectionUtilities.isOnline(view.getContext())) { if (ConnectionUtilities.isOnline(getContext())) {
swipeRefreshLayout.setRefreshing(false); new RefreshTask(getActivity(), mainView, daoSession).execute();
Toast.makeText(view.getContext(), R.string.noInternet_text, Toast.LENGTH_SHORT).show();
} else { } else {
refreshTask = new RefreshTask(); Toast.makeText(mainView.getContext(), R.string.noInternet_text, Toast.LENGTH_SHORT).show();
refreshTask.execute(((WulkanowyApp) getActivity().getApplication()).getDaoSession()); swipeRefreshLayout.setRefreshing(false);
} }
} }
}); });
if (new ArrayList<>().equals(subjectWithGradesList)) {
createExpListView();
new GradesTask().execute(((WulkanowyApp) getActivity().getApplication()).getDaoSession());
} else if (subjectWithGradesList.size() > 0) {
createExpListView();
view.findViewById(R.id.loadingPanel).setVisibility(View.GONE);
}
return view;
} }
@Override private static void createExpList(View mainView, Activity activity) {
public void onDestroyView() {
super.onDestroyView();
if (refreshTask != null && refreshTask.getStatus() == AsyncTask.Status.RUNNING) {
refreshTask.cancel(true);
}
}
private void createExpListView() { RecyclerView recyclerView = mainView.findViewById(R.id.subject_grade_recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(activity));
RecyclerView recyclerView = view.findViewById(R.id.subject_grade_recycler); GradesAdapter gradesAdapter = new GradesAdapter(subjectWithGradesList, activity);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
GradesAdapter gradesAdapter = new GradesAdapter(subjectWithGradesList, getActivity());
recyclerView.setAdapter(gradesAdapter); recyclerView.setAdapter(gradesAdapter);
} }
private void prepareSubjectsWithGradesList(DaoSession daoSession) { private static void downloadGradesFormDatabase(DaoSession daoSession) {
subjectWithGradesList = new ArrayList<>();
long userId = getContext().getSharedPreferences("LoginData", Context.MODE_PRIVATE) subjectWithGradesList = new ArrayList<>();
.getLong("userId", 0);
AccountDao accountDao = daoSession.getAccountDao(); AccountDao accountDao = daoSession.getAccountDao();
Account account = accountDao.load(userId); Account account = accountDao.load(userId);
@ -110,31 +112,54 @@ public class GradesFragment extends Fragment {
} }
} }
private class GradesTask extends AsyncTask<DaoSession, Void, Void> { private static class GenerateListTask extends AsyncTask<Void, Void, Void> {
private WeakReference<View> mainView;
private WeakReference<Activity> activity;
private DaoSession daoSession;
public GenerateListTask(Activity activity, View mainView, DaoSession daoSession) {
this.activity = new WeakReference<>(activity);
this.mainView = new WeakReference<>(mainView);
this.daoSession = daoSession;
}
@Override @Override
protected Void doInBackground(DaoSession... params) { protected Void doInBackground(Void... params) {
prepareSubjectsWithGradesList(params[0]); downloadGradesFormDatabase(daoSession);
return null; return null;
} }
protected void onPostExecute(Void result) { protected void onPostExecute(Void result) {
super.onPostExecute(result); super.onPostExecute(result);
createExpList(mainView.get(), activity.get());
createExpListView(); mainView.get().findViewById(R.id.loadingPanel).setVisibility(View.INVISIBLE);
view.findViewById(R.id.loadingPanel).setVisibility(View.GONE);
} }
} }
private class RefreshTask extends AsyncTask<DaoSession, Void, Boolean> { private static class RefreshTask extends AsyncTask<Void, Void, Boolean> {
private DaoSession daoSession;
private WeakReference<Activity> activity;
private WeakReference<View> mainView;
public RefreshTask(Activity activity, View mainView, DaoSession daoSession) {
this.activity = new WeakReference<>(activity);
this.daoSession = daoSession;
this.mainView = new WeakReference<>(mainView);
}
@Override @Override
protected Boolean doInBackground(DaoSession... params) { protected Boolean doInBackground(Void... params) {
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession()); VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession());
try { try {
vulcanSynchronization.loginCurrentUser(getContext(), params[0], new Vulcan()); vulcanSynchronization.loginCurrentUser(activity.get(), daoSession, new Vulcan());
vulcanSynchronization.syncGrades(); vulcanSynchronization.syncGrades();
prepareSubjectsWithGradesList(params[0]); downloadGradesFormDatabase(daoSession);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
Log.e(VulcanJobHelper.DEBUG_TAG, "There was a synchronization problem", e); Log.e(VulcanJobHelper.DEBUG_TAG, "There was a synchronization problem", e);
@ -147,24 +172,27 @@ public class GradesFragment extends Fragment {
super.onPostExecute(result); super.onPostExecute(result);
if (result) { if (result) {
prepareSubjectsWithGradesList(((WulkanowyApp) getActivity().getApplication()).getDaoSession()); if (mainView.get() != null && activity.get() != null) {
createExpListView(); createExpList(mainView.get(), activity.get());
swipeRefreshLayout.setRefreshing(false); }
int volumeGrades = DatabaseAccess.getNewGrades(daoSession).size();
int volumeGrades = DatabaseAccess.getNewGrades(((WulkanowyApp) getActivity().getApplication()).getDaoSession()).size();
if (volumeGrades == 0) { if (volumeGrades == 0) {
Snackbar.make(getActivity().findViewById(R.id.fragment_container), Snackbar.make(activity.get().findViewById(R.id.fragment_container),
R.string.snackbar_no_grades, R.string.snackbar_no_grades,
Snackbar.LENGTH_SHORT).show(); Snackbar.LENGTH_SHORT).show();
} else { } else {
Snackbar.make(getActivity().findViewById(R.id.fragment_container), Snackbar.make(activity.get().findViewById(R.id.fragment_container),
getString(R.string.snackbar_new_grade, volumeGrades), activity.get().getString(R.string.snackbar_new_grade, volumeGrades),
Snackbar.LENGTH_SHORT).show(); Snackbar.LENGTH_SHORT).show();
} }
} else { } else {
Toast.makeText(getContext(), R.string.refresh_error_text, Toast.LENGTH_SHORT).show(); Toast.makeText(activity.get(), R.string.refresh_error_text, Toast.LENGTH_SHORT).show();
}
if (mainView.get() != null) {
SwipeRefreshLayout swipeRefreshLayout = mainView.get().findViewById(R.id.grade_swipe_refresh);
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
} }

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.activity.dashboard.lessonplan; package io.github.wulkanowy.activity.dashboard.lessonplan;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -14,7 +15,7 @@ public class LessonPlanFragment extends Fragment {
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_lessonplan, container, false); return inflater.inflate(R.layout.fragment_lessonplan, container, false);
} }

View File

@ -144,8 +144,8 @@ public class LoginActivity extends Activity {
symbol = "Default"; symbol = "Default";
} }
String[] keys = this.getResources().getStringArray(R.array.symbols); String[] keys = getResources().getStringArray(R.array.symbols);
String[] values = this.getResources().getStringArray(R.array.symbols_values); String[] values = getResources().getStringArray(R.array.symbols_values);
LinkedHashMap<String, String> map = new LinkedHashMap<>(); LinkedHashMap<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < Math.min(keys.length, values.length); ++i) { for (int i = 0; i < Math.min(keys.length, values.length); ++i) {
@ -198,9 +198,9 @@ public class LoginActivity extends Activity {
float y = ev.getRawY() + view.getTop() - scrcoords[1]; float y = ev.getRawY() + view.getTop() - scrcoords[1];
if (x < view.getLeft() || x > view.getRight() || y < view.getTop() if (x < view.getLeft() || x > view.getRight() || y < view.getTop()
|| y > view.getBottom()) { || y > view.getBottom()) {
((InputMethodManager) this.getSystemService( ((InputMethodManager) getSystemService(
Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow( Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(
(this.getWindow().getDecorView().getApplicationWindowToken()), 0); (getWindow().getDecorView().getApplicationWindowToken()), 0);
} }
} }
} }

View File

@ -12,21 +12,19 @@ import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.WulkanowyApp; import io.github.wulkanowy.activity.WulkanowyApp;
import io.github.wulkanowy.activity.dashboard.DashboardActivity; import io.github.wulkanowy.activity.dashboard.DashboardActivity;
import io.github.wulkanowy.api.Cookies;
import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException; import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException; import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.Login;
import io.github.wulkanowy.api.login.NotLoggedInErrorException; import io.github.wulkanowy.api.login.NotLoggedInErrorException;
import io.github.wulkanowy.dao.entities.DaoSession; import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException; import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.LoginSession; import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.VulcanSynchronization; import io.github.wulkanowy.services.VulcanSynchronization;
import io.github.wulkanowy.services.synchronisation.AccountRegistration; import io.github.wulkanowy.services.jobs.GradeJob;
import io.github.wulkanowy.utilities.ConnectionUtilities; import io.github.wulkanowy.utilities.ConnectionUtilities;
/** /**
@ -41,16 +39,16 @@ public class LoginTask extends AsyncTask<Void, String, Integer> {
private final String symbol; private final String symbol;
private Activity activity; private WeakReference<Activity> activity;
private View progressView; private WeakReference<View> progressView;
private View loginFormView; private WeakReference<View> loginFormView;
private TextView showText; private WeakReference<TextView> showText;
public LoginTask(Activity activity, String email, String password, String symbol) { public LoginTask(Activity activity, String email, String password, String symbol) {
this.activity = activity; this.activity = new WeakReference<>(activity);
this.email = email; this.email = email;
this.password = password; this.password = password;
this.symbol = symbol; this.symbol = symbol;
@ -58,28 +56,24 @@ public class LoginTask extends AsyncTask<Void, String, Integer> {
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
showText = activity.findViewById(R.id.login_progress_text); showText = new WeakReference<>((TextView) activity.get().findViewById(R.id.login_progress_text));
} }
@Override @Override
protected Integer doInBackground(Void... params) { protected Integer doInBackground(Void... params) {
if (ConnectionUtilities.isOnline(activity)) { if (ConnectionUtilities.isOnline(activity.get())) {
AccountRegistration accountRegistration = new AccountRegistration( VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(new LoginSession());
new Login(new Cookies()),
new Vulcan(),
email, password, symbol);
DaoSession daoSession = ((WulkanowyApp) activity.getApplication()).getDaoSession(); DaoSession daoSession = ((WulkanowyApp) activity.get().getApplication()).getDaoSession();
try { try {
publishProgress("1", activity.getResources().getString(R.string.step_connecting)); publishProgress("1", activity.get().getResources().getString(R.string.step_connecting));
String certificate = accountRegistration.connect(); vulcanSynchronization.firstLoginConnectStep(email, password, symbol);
publishProgress("2", activity.getResources().getString(R.string.step_login)); publishProgress("2", activity.get().getResources().getString(R.string.step_login));
LoginSession loginSession = accountRegistration.login(activity, daoSession, certificate); vulcanSynchronization.firstLoginSignInStep(activity.get(), daoSession);
publishProgress("3", activity.getResources().getString(R.string.step_synchronization)); publishProgress("3", activity.get().getResources().getString(R.string.step_synchronization));
VulcanSynchronization vulcanSynchronization = new VulcanSynchronization(loginSession);
vulcanSynchronization.syncSubjectsAndGrades(); vulcanSynchronization.syncSubjectsAndGrades();
} catch (BadCredentialsException e) { } catch (BadCredentialsException e) {
@ -92,7 +86,8 @@ public class LoginTask extends AsyncTask<Void, String, Integer> {
return R.string.login_denied_text; return R.string.login_denied_text;
} }
accountRegistration.scheduleSynchronization(activity); GradeJob gradeJob = new GradeJob();
gradeJob.scheduledJob(activity.get());
return R.string.login_accepted_text; return R.string.login_accepted_text;
@ -103,7 +98,7 @@ public class LoginTask extends AsyncTask<Void, String, Integer> {
@Override @Override
protected void onProgressUpdate(String... progress) { protected void onProgressUpdate(String... progress) {
showText.setText(progress[0] + "/3 - " + progress[1] + "..."); showText.get().setText(String.format("%1$s/3 - %2$s...", progress[0], progress[1]));
} }
@Override @Override
@ -113,33 +108,32 @@ public class LoginTask extends AsyncTask<Void, String, Integer> {
switch (messageID) { switch (messageID) {
// if success // if success
case R.string.login_accepted_text: case R.string.login_accepted_text:
Intent intent = new Intent(activity, DashboardActivity.class); Intent intent = new Intent(activity.get(), DashboardActivity.class);
activity.finish(); activity.get().finish();
activity.startActivity(intent); activity.get().startActivity(intent);
break; break;
// if bad credentials entered // if bad credentials entered
case R.string.login_bad_credentials_text: case R.string.login_bad_credentials_text:
EditText passwordView = activity.findViewById(R.id.password); EditText passwordView = activity.get().findViewById(R.id.password);
passwordView.setError(activity.getString(R.string.error_incorrect_password)); passwordView.setError(activity.get().getString(R.string.error_incorrect_password));
passwordView.requestFocus(); passwordView.requestFocus();
break; break;
// if no permission // if no permission
case R.string.error_bad_account_permission: case R.string.error_bad_account_permission:
// Change to visible symbol input view // Change to visible symbol input view
TextInputLayout symbolLayout = activity.findViewById(R.id.to_symbol_input_layout); TextInputLayout symbolLayout = activity.get().findViewById(R.id.to_symbol_input_layout);
symbolLayout.setVisibility(View.VISIBLE); symbolLayout.setVisibility(View.VISIBLE);
EditText symbolView = activity.findViewById(R.id.symbol); EditText symbolView = activity.get().findViewById(R.id.symbol);
symbolView.setError(activity.getString(R.string.error_bad_account_permission)); symbolView.setError(activity.get().getString(R.string.error_bad_account_permission));
symbolView.requestFocus(); symbolView.requestFocus();
break; break;
default: default:
Snackbar Snackbar.make(activity.get().findViewById(R.id.coordinatorLayout),
.make(activity.findViewById(R.id.coordinatorLayout), messageID, Snackbar.LENGTH_LONG) messageID, Snackbar.LENGTH_LONG).show();
.show();
break; break;
} }
} }
@ -153,33 +147,33 @@ public class LoginTask extends AsyncTask<Void, String, Integer> {
* Shows the progress UI and hides the login form. * Shows the progress UI and hides the login form.
*/ */
public void showProgress(final boolean show) { public void showProgress(final boolean show) {
loginFormView = activity.findViewById(R.id.login_form); loginFormView = new WeakReference<>(activity.get().findViewById(R.id.login_form));
progressView = activity.findViewById(R.id.login_progress); progressView = new WeakReference<>(activity.get().findViewById(R.id.login_progress));
int animTime = activity.getResources().getInteger(android.R.integer.config_shortAnimTime); int animTime = activity.get().getResources().getInteger(android.R.integer.config_shortAnimTime);
changeLoginFormVisibility(show, animTime); changeLoginFormVisibility(show, animTime);
changeProgressVisibility(show, animTime); changeProgressVisibility(show, animTime);
} }
private void changeLoginFormVisibility(final boolean show, final int animTime) { private void changeLoginFormVisibility(final boolean show, final int animTime) {
loginFormView.setVisibility(show ? View.GONE : View.VISIBLE); loginFormView.get().setVisibility(show ? View.GONE : View.VISIBLE);
loginFormView.animate().setDuration(animTime).alpha( loginFormView.get().animate().setDuration(animTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() { show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
loginFormView.setVisibility(show ? View.GONE : View.VISIBLE); loginFormView.get().setVisibility(show ? View.GONE : View.VISIBLE);
} }
}); });
} }
private void changeProgressVisibility(final boolean show, final int animTime) { private void changeProgressVisibility(final boolean show, final int animTime) {
progressView.setVisibility(show ? View.VISIBLE : View.GONE); progressView.get().setVisibility(show ? View.VISIBLE : View.GONE);
progressView.animate().setDuration(animTime).alpha( progressView.get().animate().setDuration(animTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() { show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
progressView.setVisibility(show ? View.VISIBLE : View.GONE); progressView.get().setVisibility(show ? View.VISIBLE : View.GONE);
} }
}); });
} }

View File

@ -1,53 +0,0 @@
package io.github.wulkanowy.activity.splash;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.widget.Toast;
import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.dashboard.DashboardActivity;
import io.github.wulkanowy.activity.login.LoginActivity;
import io.github.wulkanowy.services.jobs.GradeJob;
import io.github.wulkanowy.utilities.ConnectionUtilities;
public class LoadingTask extends AsyncTask<Void, Void, Boolean> {
private Context context;
LoadingTask(Context context) {
this.context = context;
}
@Override
protected Boolean doInBackground(Void... voids) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ConnectionUtilities.isOnline(context);
}
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (!result) {
Toast.makeText(context, R.string.noInternet_text, Toast.LENGTH_LONG).show();
}
if (context.getSharedPreferences("LoginData", Context.MODE_PRIVATE).getLong("userId", 0) == 0) {
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
} else {
GradeJob gradesSync = new GradeJob();
gradesSync.scheduledJob(context);
Intent intent = new Intent(context, DashboardActivity.class);
context.startActivity(intent);
}
}
}

View File

@ -1,11 +1,17 @@
package io.github.wulkanowy.activity.splash; package io.github.wulkanowy.activity.splash;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.widget.TextView; import android.widget.TextView;
import io.github.wulkanowy.BuildConfig; import io.github.wulkanowy.BuildConfig;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
import io.github.wulkanowy.activity.dashboard.DashboardActivity;
import io.github.wulkanowy.activity.login.LoginActivity;
import io.github.wulkanowy.services.jobs.GradeJob;
public class SplashActivity extends AppCompatActivity { public class SplashActivity extends AppCompatActivity {
@ -15,8 +21,26 @@ public class SplashActivity extends AppCompatActivity {
setContentView(R.layout.activity_splash); setContentView(R.layout.activity_splash);
TextView versionName = findViewById(R.id.rawText); TextView versionName = findViewById(R.id.rawText);
versionName.setText(getText(R.string.version_text) + BuildConfig.VERSION_NAME); versionName.setText(getString(R.string.version_text, BuildConfig.VERSION_NAME));
new LoadingTask(this).execute(); new Handler().postDelayed(new Runnable() {
@Override
public void run() {
executeOnRunApp();
}
}, 500);
}
private void executeOnRunApp() {
if (getSharedPreferences("LoginData", Context.MODE_PRIVATE).getLong("userId", 0) == 0) {
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
} else {
GradeJob gradesSync = new GradeJob();
gradesSync.scheduledJob(this);
Intent intent = new Intent(this, DashboardActivity.class);
startActivity(intent);
}
} }
} }

View File

@ -18,9 +18,9 @@ public abstract class EntitiesCompare {
List<Grade> lastList = new ArrayList<>(); List<Grade> lastList = new ArrayList<>();
for (Grade grade : addedOrUpdatedGradeList) { for (Grade grade : addedOrUpdatedGradeList) {
grade.setIsNew(true);
if (oldList.size() != 0) { if (oldList.size() != 0) {
grade.setRead(false); grade.setRead(false);
grade.setIsNew(true);
} }
updatedList.add(grade); updatedList.add(grade);
} }

View File

@ -12,13 +12,11 @@ public class Safety extends Scrambler {
public String encrypt(String email, String plainText, Context context) throws CryptoException, UnsupportedOperationException { public String encrypt(String email, String plainText, Context context) throws CryptoException, UnsupportedOperationException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
loadKeyStore(); loadKeyStore();
generateNewKey(email, context); generateNewKey(email, context);
return encryptString(email, plainText); return encryptString(email, plainText);
} else { } else {
if (!RootUtilities.isRooted()) {
if (RootUtilities.isRooted()) {
return new String(Base64.encode(plainText.getBytes(), Base64.DEFAULT)); return new String(Base64.encode(plainText.getBytes(), Base64.DEFAULT));
} else { } else {
Log.e(Scrambler.DEBUG_TAG, "Password store in this devices isn't safe because is rooted"); Log.e(Scrambler.DEBUG_TAG, "Password store in this devices isn't safe because is rooted");
@ -30,7 +28,6 @@ public class Safety extends Scrambler {
public String decrypt(String email, String encryptedText) throws CryptoException { public String decrypt(String email, String encryptedText) throws CryptoException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
loadKeyStore(); loadKeyStore();
return decryptString(email, encryptedText); return decryptString(email, encryptedText);
} else { } else {

View File

@ -36,7 +36,7 @@ public class Scrambler {
private KeyStore keyStore; private KeyStore keyStore;
public void loadKeyStore() throws CryptoException { protected void loadKeyStore() throws CryptoException {
try { try {
keyStore = KeyStore.getInstance(ANDROID_KEYSTORE); keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);

View File

@ -5,14 +5,18 @@ import android.util.Log;
import java.io.IOException; import java.io.IOException;
import io.github.wulkanowy.api.Cookies;
import io.github.wulkanowy.api.Vulcan; import io.github.wulkanowy.api.Vulcan;
import io.github.wulkanowy.api.login.AccountPermissionException; import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException; import io.github.wulkanowy.api.login.BadCredentialsException;
import io.github.wulkanowy.api.login.Login;
import io.github.wulkanowy.api.login.LoginErrorException; 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.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException; import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.services.jobs.VulcanJobHelper; import io.github.wulkanowy.services.jobs.VulcanJobHelper;
import io.github.wulkanowy.services.synchronisation.AccountAuthorization; import io.github.wulkanowy.services.synchronisation.CurrentAccountLogin;
import io.github.wulkanowy.services.synchronisation.FirstAccountLogin;
import io.github.wulkanowy.services.synchronisation.GradesSynchronisation; import io.github.wulkanowy.services.synchronisation.GradesSynchronisation;
import io.github.wulkanowy.services.synchronisation.SubjectsSynchronisation; import io.github.wulkanowy.services.synchronisation.SubjectsSynchronisation;
@ -20,20 +24,39 @@ public class VulcanSynchronization {
private LoginSession loginSession; private LoginSession loginSession;
private FirstAccountLogin firstAccountLogin;
private String certificate;
public VulcanSynchronization(LoginSession loginSession) { public VulcanSynchronization(LoginSession loginSession) {
this.loginSession = loginSession; this.loginSession = loginSession;
} }
public void firstLoginConnectStep(String email, String password, String symbol)
throws BadCredentialsException, IOException {
firstAccountLogin = new FirstAccountLogin(new Login(new Cookies()), new Vulcan(), email, password, symbol);
certificate = firstAccountLogin.connect();
}
public void firstLoginSignInStep(Context context, DaoSession daoSession)
throws NotLoggedInErrorException, AccountPermissionException, IOException, CryptoException {
if (firstAccountLogin != null && certificate != null) {
loginSession = firstAccountLogin.login(context, daoSession, certificate);
} else {
Log.e(VulcanJobHelper.DEBUG_TAG, "Before first login, should call firstLoginConnectStep",
new UnsupportedOperationException());
}
}
public void loginCurrentUser(Context context, DaoSession daoSession, Vulcan vulcan) public void loginCurrentUser(Context context, DaoSession daoSession, Vulcan vulcan)
throws CryptoException, BadCredentialsException, AccountPermissionException, LoginErrorException, IOException { throws CryptoException, BadCredentialsException, AccountPermissionException, LoginErrorException, IOException {
CurrentAccountLogin currentAccountLogin = new CurrentAccountLogin(context, daoSession, vulcan);
AccountAuthorization accountAuthorization = new AccountAuthorization(context, daoSession, vulcan); loginSession = currentAccountLogin.loginCurrentUser();
loginSession = accountAuthorization.loginCurrentUser();
} }
public boolean syncGrades() { public boolean syncGrades() {
if (loginSession != null) {
GradesSynchronisation gradesSynchronisation = new GradesSynchronisation(); GradesSynchronisation gradesSynchronisation = new GradesSynchronisation();
try { try {
gradesSynchronisation.sync(loginSession); gradesSynchronisation.sync(loginSession);
return true; return true;
@ -41,11 +64,16 @@ public class VulcanSynchronization {
Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of grades failed", e); Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of grades failed", e);
return false; return false;
} }
} else {
Log.e(VulcanJobHelper.DEBUG_TAG, "Before synchronization, should login user to log",
new UnsupportedOperationException());
return false;
}
} }
public boolean syncSubjectsAndGrades() { public boolean syncSubjectsAndGrades() {
if (loginSession != null) {
SubjectsSynchronisation subjectsSynchronisation = new SubjectsSynchronisation(); SubjectsSynchronisation subjectsSynchronisation = new SubjectsSynchronisation();
try { try {
subjectsSynchronisation.sync(loginSession); subjectsSynchronisation.sync(loginSession);
syncGrades(); syncGrades();
@ -54,5 +82,10 @@ public class VulcanSynchronization {
Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of subjects failed", e); Log.e(VulcanJobHelper.DEBUG_TAG, "Synchronisation of subjects failed", e);
return false; return false;
} }
} else {
Log.e(VulcanJobHelper.DEBUG_TAG, "Before synchronization, should login user to log",
new UnsupportedOperationException());
return false;
}
} }
} }

View File

@ -21,11 +21,11 @@ import io.github.wulkanowy.services.VulcanSynchronization;
public class GradeJob extends VulcanJobHelper { public class GradeJob extends VulcanJobHelper {
public static final String UNIQUE_TAG = "GradesSync34512"; private static final String UNIQUE_TAG = "GradesSync34512";
public static final int DEFAULT_INTERVAL_START = 60 * 50; private static final int DEFAULT_INTERVAL_START = 60 * 50;
public static final int DEFAULT_INTERVAL_END = DEFAULT_INTERVAL_START + (60 * 10); private static final int DEFAULT_INTERVAL_END = DEFAULT_INTERVAL_START + (60 * 10);
@Override @Override
protected Job createJob(FirebaseJobDispatcher dispatcher) { protected Job createJob(FirebaseJobDispatcher dispatcher) {

View File

@ -21,11 +21,11 @@ import io.github.wulkanowy.services.VulcanSynchronization;
public class SubjectJob extends VulcanJobHelper { public class SubjectJob extends VulcanJobHelper {
public static final String UNIQUE_TAG = "SubjectsSync34512"; private static final String UNIQUE_TAG = "SubjectsSync34512";
public static final int DEFAULT_INTERVAL_START = 0; private static final int DEFAULT_INTERVAL_START = 0;
public static final int DEFAULT_INTERVAL_END = DEFAULT_INTERVAL_START + 10; private static final int DEFAULT_INTERVAL_END = DEFAULT_INTERVAL_START + 10;
@Override @Override
protected Job createJob(FirebaseJobDispatcher dispatcher) { protected Job createJob(FirebaseJobDispatcher dispatcher) {

View File

@ -7,6 +7,7 @@ import com.firebase.jobdispatcher.JobParameters;
import com.firebase.jobdispatcher.JobService; import com.firebase.jobdispatcher.JobService;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference;
import io.github.wulkanowy.api.login.AccountPermissionException; import io.github.wulkanowy.api.login.AccountPermissionException;
import io.github.wulkanowy.api.login.BadCredentialsException; import io.github.wulkanowy.api.login.BadCredentialsException;
@ -15,35 +16,47 @@ import io.github.wulkanowy.security.CryptoException;
public abstract class VulcanService extends JobService { public abstract class VulcanService extends JobService {
private SyncTask syncTask = new SyncTask(); private SyncTask syncTask;
@Override @Override
public boolean onStartJob(JobParameters params) { public boolean onStartJob(JobParameters params) {
Log.d(VulcanJobHelper.DEBUG_TAG, "Wulkanowy services start"); Log.d(VulcanJobHelper.DEBUG_TAG, "Wulkanowy services start");
syncTask.execute(params); syncTask = new SyncTask(this, params);
syncTask.execute();
return true; return true;
} }
@Override @Override
public boolean onStopJob(JobParameters params) { public boolean onStopJob(JobParameters params) {
Log.e(VulcanJobHelper.DEBUG_TAG, "Wulkanowy serives stop"); Log.e(VulcanJobHelper.DEBUG_TAG, "Wulkanowy services stop");
if (syncTask != null) {
syncTask.cancel(true); syncTask.cancel(true);
}
return true; return true;
} }
public abstract void workToBePerformed() throws CryptoException, BadCredentialsException, public abstract void workToBePerformed() throws CryptoException, BadCredentialsException,
NotLoggedInErrorException, AccountPermissionException, IOException; NotLoggedInErrorException, AccountPermissionException, IOException;
private class SyncTask extends AsyncTask<JobParameters, Void, Void> { private static class SyncTask extends AsyncTask<Void, Void, Void> {
private JobParameters jobParameters;
private WeakReference<VulcanService> vulcanService;
public SyncTask(VulcanService vulcanService, JobParameters jobParameters) {
this.jobParameters = jobParameters;
this.vulcanService = new WeakReference<>(vulcanService);
}
@Override @Override
protected Void doInBackground(JobParameters... params) { protected Void doInBackground(Void... voids) {
try { try {
workToBePerformed(); vulcanService.get().workToBePerformed();
} catch (Exception e) { } catch (Exception e) {
Log.e(VulcanJobHelper.DEBUG_TAG, "User logging in the background failed", e); Log.e(VulcanJobHelper.DEBUG_TAG, "User logging in the background failed", e);
} finally { } finally {
jobFinished(params[0], false); vulcanService.get().jobFinished(jobParameters, false);
} }
return null; return null;
} }

View File

@ -17,7 +17,7 @@ import io.github.wulkanowy.security.Safety;
import io.github.wulkanowy.services.LoginSession; import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.jobs.VulcanJobHelper; import io.github.wulkanowy.services.jobs.VulcanJobHelper;
public class AccountAuthorization { public class CurrentAccountLogin {
private final Context context; private final Context context;
@ -25,7 +25,7 @@ public class AccountAuthorization {
private final Vulcan vulcan; private final Vulcan vulcan;
public AccountAuthorization(Context context, DaoSession daoSession, Vulcan vulcan) { public CurrentAccountLogin(Context context, DaoSession daoSession, Vulcan vulcan) {
this.context = context; this.context = context;
this.daoSession = daoSession; this.daoSession = daoSession;
this.vulcan = vulcan; this.vulcan = vulcan;

View File

@ -16,9 +16,8 @@ import io.github.wulkanowy.dao.entities.DaoSession;
import io.github.wulkanowy.security.CryptoException; import io.github.wulkanowy.security.CryptoException;
import io.github.wulkanowy.security.Safety; import io.github.wulkanowy.security.Safety;
import io.github.wulkanowy.services.LoginSession; import io.github.wulkanowy.services.LoginSession;
import io.github.wulkanowy.services.jobs.GradeJob;
public class AccountRegistration { public class FirstAccountLogin {
private final Login login; private final Login login;
@ -31,7 +30,7 @@ public class AccountRegistration {
private final String symbol; private final String symbol;
public AccountRegistration(Login login, Vulcan vulcan, String email, String password, String symbol) { public FirstAccountLogin(Login login, Vulcan vulcan, String email, String password, String symbol) {
this.login = login; this.login = login;
this.vulcan = vulcan; this.vulcan = vulcan;
this.email = email; this.email = email;
@ -74,9 +73,4 @@ public class AccountRegistration {
.setUserId(userId) .setUserId(userId)
.setDaoSession(daoSession); .setDaoSession(daoSession);
} }
public void scheduleSynchronization(Context context) {
GradeJob gradesSync = new GradeJob();
gradesSync.scheduledJob(context);
}
} }

View File

@ -9,7 +9,11 @@ public abstract class ConnectionUtilities {
public static boolean isOnline(Context context) { public static boolean isOnline(Context context) {
ConnectivityManager connectivityManager = ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnectedOrConnecting(); return networkInfo != null && networkInfo.isConnectedOrConnecting();
} else {
return false;
}
} }
} }

View File

@ -8,8 +8,6 @@ import java.io.File;
abstract public class RootUtilities { abstract public class RootUtilities {
public static boolean isRooted() { public static boolean isRooted() {
String buildTags = Build.TAGS; String buildTags = Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) { if (buildTags != null && buildTags.contains("test-keys")) {
return true; return true;
@ -23,7 +21,6 @@ abstract public class RootUtilities {
} catch (Exception e1) { } catch (Exception e1) {
// ignore // ignore
} }
return canExecuteCommand("/system/xbin/which su") return canExecuteCommand("/system/xbin/which su")
|| canExecuteCommand("/system/bin/which su") || canExecuteCommand("which su"); || canExecuteCommand("/system/bin/which su") || canExecuteCommand("which su");
} }
@ -36,7 +33,6 @@ abstract public class RootUtilities {
} catch (Exception e) { } catch (Exception e) {
executedSuccesfully = false; executedSuccesfully = false;
} }
return executedSuccesfully; return executedSuccesfully;
} }
} }

View File

@ -5,16 +5,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="io.github.wulkanowy.activity.dashboard.grades.GradesFragment"> tools:context="io.github.wulkanowy.activity.dashboard.grades.GradesFragment">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/grade_swipe_refresh"
android:layout_width="match_parent"
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 <RelativeLayout
android:id="@+id/loadingPanel" android:id="@+id/loadingPanel"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -27,6 +17,16 @@
android:indeterminate="true" /> android:indeterminate="true" />
</RelativeLayout> </RelativeLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/grade_swipe_refresh"
android:layout_width="match_parent"
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" />
</android.support.v4.widget.SwipeRefreshLayout> </android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>

View File

@ -8,7 +8,7 @@
android:layout_marginLeft="5dp" android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" android:layout_marginRight="5dp"
android:layout_marginStart="5dp" android:layout_marginStart="5dp"
android:layout_marginTop="5dp" android:layout_marginBottom="10dp"
android:foreground="?attr/selectableItemBackgroundBorderless" android:foreground="?attr/selectableItemBackgroundBorderless"
card_view:cardElevation="0dp"> card_view:cardElevation="0dp">
@ -19,8 +19,7 @@
android:layout_marginEnd="7dp" android:layout_marginEnd="7dp"
android:layout_marginLeft="7dp" android:layout_marginLeft="7dp"
android:layout_marginRight="7dp" android:layout_marginRight="7dp"
android:layout_marginStart="7dp" android:layout_marginStart="7dp">
android:layout_marginTop="7dp">
<TextView <TextView
android:id="@+id/grade_text" android:id="@+id/grade_text"

View File

@ -32,7 +32,7 @@
<string name="noInternet_text">Brak połączenia z internetem</string> <string name="noInternet_text">Brak połączenia z internetem</string>
<string name="root_failed_text">To urządzenie posiada posiada podwyższone uprawnienia (root). Automatyczne logowanie zosatło wyłączone.</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="encrypt_failed_text">Szyfrowanie nie powiodło się. Automatyczne logowanie zostało wyłączone</string>
<string name="version_text">Wersja\u0020</string> <string name="version_text">Wersja %1$s</string>
<string name="dialog_description_text">Opis</string> <string name="dialog_description_text">Opis</string>
<string name="dialog_weight_text">Waga</string> <string name="dialog_weight_text">Waga</string>
<string name="noDescription_text">Brak opisu</string> <string name="noDescription_text">Brak opisu</string>

View File

@ -23,29 +23,33 @@
<string name="action_create_account">No account yet? Create one</string> <string name="action_create_account">No account yet? Create one</string>
<string name="action_forgot_password">Forgot password?</string> <string name="action_forgot_password">Forgot password?</string>
<string name="color_black_text">Black</string>
<string name="color_red_text">Red</string>
<string name="color_blue_text">Blue</string>
<string name="color_green_text">Green</string>
<string name="noColor_text">No color</string>
<string name="activity_dashboard_text">Dashboard Activity</string> <string name="activity_dashboard_text">Dashboard Activity</string>
<string name="dashboard_text">Dashboard</string> <string name="dashboard_text">Dashboard</string>
<string name="grades_text">Grades</string> <string name="grades_text">Grades</string>
<string name="attendance_text">Attendance</string> <string name="attendance_text">Attendance</string>
<string name="lessonplan_text">Lesson Plan</string> <string name="lessonplan_text">Lesson Plan</string>
<string name="settings_text">Settings</string> <string name="settings_text">Settings</string>
<string name="noInternet_text">No internet connection</string> <string name="noInternet_text">No internet connection</string>
<string name="root_failed_text">This device is rooted. Automatic login has been disabled</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="encrypt_failed_text">Encryption failed. Automatic login has been disabled</string>
<string name="version_text">Version\u0020</string> <string name="version_text">Version %1$s</string>
<string name="refresh_error_text">An error occurred while refreshing the content.</string>
<string name="dialog_description_text">Description</string> <string name="dialog_description_text">Description</string>
<string name="dialog_weight_text">Weight</string> <string name="dialog_weight_text">Weight</string>
<string name="noDescription_text">No description</string> <string name="noDescription_text">No description</string>
<string name="dialog_teacher_text">Teacher</string> <string name="dialog_teacher_text">Teacher</string>
<string name="dialog_date_text">Date</string> <string name="dialog_date_text">Date</string>
<string name="dialog_color_text">Color</string> <string name="dialog_color_text">Color</string>
<string name="color_black_text">Black</string>
<string name="color_red_text">Red</string>
<string name="color_blue_text">Blue</string>
<string name="color_green_text">Green</string>
<string name="noColor_text">No color</string>
<string name="dialog_close">Close</string> <string name="dialog_close">Close</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_no_grades">No new grades</string>
<string name="snackbar_new_grade">Number of new grades: %1$d</string> <string name="snackbar_new_grade">Number of new grades: %1$d</string>

View File

@ -46,16 +46,28 @@ public class EntitiesCompareTest extends EntitiesCompare {
} }
@Test @Test
public void testCompareNewGradePositive() { public void testCompareNewGradeEmptyOldList() {
newList.add(grade1); newList.add(grade1);
List<Grade> updatedList = EntitiesCompare.compareGradeList(newList, oldList); List<Grade> updatedList = EntitiesCompare.compareGradeList(newList, oldList);
Assert.assertEquals(true, (updatedList.get(0)).getIsNew()); Assert.assertFalse(updatedList.get(0).getIsNew());
} }
@Test
public void testCompareNewGradePositive() {
newList.add(grade1);
newList.add(grade2);
oldList.add(grade2);
List<Grade> updatedList = EntitiesCompare.compareGradeList(newList, oldList);
Assert.assertFalse(updatedList.get(0).getIsNew());
Assert.assertTrue(updatedList.get(1).getIsNew());
}
@Test @Test
public void testCompareNewGradeNegative() { public void testCompareNewGradeNegative() {
@ -66,8 +78,8 @@ public class EntitiesCompareTest extends EntitiesCompare {
List<Grade> updatedList = EntitiesCompare.compareGradeList(newList, oldList); List<Grade> updatedList = EntitiesCompare.compareGradeList(newList, oldList);
Assert.assertEquals(false, (updatedList.get(0)).getIsNew()); Assert.assertFalse(updatedList.get(0).getIsNew());
Assert.assertEquals(false, (updatedList.get(1)).getIsNew()); Assert.assertFalse(updatedList.get(1).getIsNew());
} }
@Test @Test
@ -77,4 +89,18 @@ public class EntitiesCompareTest extends EntitiesCompare {
Assert.assertEquals(new ArrayList<>(), updatedList); Assert.assertEquals(new ArrayList<>(), updatedList);
} }
@Test
public void testCompareReadGradeTest() {
newList.add(grade1);
newList.add(grade2);
oldList.add(grade2.setRead(true));
List<Grade> updatedList = EntitiesCompare.compareGradeList(newList, oldList);
Assert.assertTrue(updatedList.get(0).getRead());
Assert.assertFalse(updatedList.get(0).getIsNew());
Assert.assertFalse(updatedList.get(1).getRead());
Assert.assertTrue(updatedList.get(1).getIsNew());
}
} }